function App() {
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
<div>
{mutation.isLoading ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
<button
onClick={() => {
mutation.mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
}
mutate
함수를 호출 할 때 single variable or object를 전달하는 것을 알수 있다. invalidateQueries
메소드와 setQueryData
메소드를 함께 사용하면 mutations 는 훨씬 파워풀한 툴이 된다.주의!
mutate
함수는 비동기함수이다. 따라서, 리액트 16이하 버전에서는 이벤트콜백으로 직접적으로 쓰지 않아야 한다.
onSubmit
이벤트에 접근하고 싶다면mutate
함수를 다른 함수로 감싸야 한다. ( React event pooling 때문)
// 리액트16 이하 버전에서는 작동 안함
const CreateTodo = () => {
const mutation = useMutation(event => {
event.preventDefault()
return fetch('/api', new FormData(event.target))
})
return <form onSubmit={mutation.mutate}>...</form>
}
// 이렇게 해야 작동함
const CreateTodo = () => {
const mutation = useMutation(formData => {
return fetch('/api', formData)
})
const onSubmit = event => {
event.preventDefault()
mutation.mutate(new FormData(event.target))
}
return <form onSubmit={onSubmit}>...</form>
}
data
나 error
를 제거하고 싶을 때가 있는데, reset
함수를 사용하면 된다. const CreateTodo = () => {
const [title, setTitle] = useState('')
const mutation = useMutation(createTodo)
const onCreateTodo = e => {
e.preventDefault()
mutation.mutate({ title })
}
return (
<form onSubmit={onCreateTodo}>
{mutation.error && (
<h5 onClick={() => mutation.reset()}>{mutation.error}</h5>
)}
<input
type="text"
value={title}
onChange={e => setTitle(e.target.value)}
/>
<br />
<button type="submit">Create Todo</button>
</form>
)
}
useMutation
몇가지 헬퍼 옵션이 제공된다. 이를 통해서 mutation가 작동하는 각 스테이지마다 빠르고 쉽게 side-effects를 가능하게 한다. useMutation(addTodo, {
onMutate: variables => {
// mutation이 작동할 때 로직
// 옵셔널하게 데이터를 포함하는 context를 리턴한다.
return { id: 1 }
},
onError: (error, variables, context) => {
// 에러 발생시
console.log(`rolling back optimistic update with id ${context.id}`)
},
onSuccess: (data, variables, context) => {
// 쿼리 성공시
},
onSettled: (data, error, variables, context) => {
// 에러, 성공에 관계 없이
},
})
onSuccess
, onError
, onSettled
콜백들을 사용하는 것과 약간 차이가 있다.mutate
함수가 호출될 때마다 mutation observer
가 제거되고 매번 다시 구독되기 때문이다.useMutation
핸들러들은 모든 mutate
콜을 실행시킨다.주의
useMutation
에 전달되는mutationFn
는 아마 비동기 함수일건데, 이 경우 mutations 가 종료되는 순서는 호출 순서와 다를 수 있다.
useMutation(addTodo, {
onSuccess: (data, error, variables, context) => {
// 3번 호출될 예정
},
})
['Todo 1', 'Todo 2', 'Todo 3'].forEach((todo) => {
mutate(todo, {
onSuccess: (data, error, variables, context) => {
// 어떤 mutation 이 제일 먼저 resolve 되는지와 관계 없이
// 마지막 mutation인 Todo 3 에 대해 딱 한번만 실행된다.
},
})
})
resolve
나 error
를 리턴할 Promise
를 갖고 싶다면 mutate
대신에 mutateAsync
를 사용해라.const mutation = useMutation(addTodo)
try {
const todo = await mutation.mutateAsync(todo)
console.log(todo)
} catch (error) {
console.error(error)
} finally {
console.log('done')
}
const queryClient = new QueryClient()
// "addTodo" mutation 정의하기
queryClient.setMutationDefaults('addTodo', {
mutationFn: addTodo,
onMutate: async (variables) => {
// todos list 에 대한 현재 쿼리들을 취소한다.
await queryClient.cancelQueries('todos')
// optimistic todo 생성
const optimisticTodo = { id: uuid(), title: variables.title }
// todos list 에다 optimistic todo 를 추가
queryClient.setQueryData('todos', old => [...old, optimisticTodo])
// optimistic todo 를 담은 context 를 리턴
return { optimisticTodo }
},
onSuccess: (result, variables, context) => {
// todos list 의 optimistic todo 를 result 로 교체한다.
queryClient.setQueryData('todos', old => old.map(todo => todo.id === context.optimisticTodo.id ? result : todo))
},
onError: (error, variables, context) => {
// todo list 에서 optimistic todo 를 삭제한다.
queryClient.setQueryData('todos', old => old.filter(todo => todo.id !== context.optimisticTodo.id))
},
retry: 3,
})
// 컴포넌트에서 mutation 시작
const mutation = useMutation('addTodo')
mutation.mutate({ title: 'title' })
// 만약에 디바이스가 오프라인이 된다거나 해서 mutation 이 멈추게 된다면,
// 애플리케이션이 종료될 때 멈춘 mutation 이 dehydrated 될 것이다.
const state = dehydrate(queryClient)
// 다시 애플리케이션이 작동하면 이 mutation 은 다시 hydrated 된다.
hydrate(queryClient, state)
// 멈춘 mutation를 다시 시작
queryClient.resumePausedMutations()
https://react-query-v3.tanstack.com/reference/useMutation
const {
data,
error,
isError,
isIdle,
isLoading,
isPaused,
isSuccess,
mutate,
mutateAsync,
reset,
status,
} = useMutation(mutationFn, {
mutationKey,
onError,
onMutate,
onSettled,
onSuccess,
retry,
retryDelay,
useErrorBoundary,
meta,
})
mutate(variables, {
onError,
onSettled,
onSuccess,
})
mutationFn: (variables: TVariables) => Promise<TData>
promise
를 리턴하는 함수 (일명 mutation 함수)variables
는 mutationFn
에 넣어서 mutate
시킬 오브젝트
이다. 옵션명 | 타입 | default | 설명 |
---|---|---|---|
mutationKey | mutationKey: string | mutationKey값은 queryClient.setMutationDefaults 또는 devtools 의 the mutation로 세팅 가능 | |
onError | (err: TError, variables: TVariables, context?: TContext) => Promise | void | mutation이 error를 만났을때 작동하는 함수 promise가 리턴되면 await였다가 resolve한다 | |
onMutate | (variables: TVariables) => Promise<TContext | void> | TContext | void | mutation함수가 작동하면 동일한 변수들을 인자로 실행될 함수 리턴되는 값은 onSettled 와 onError 에 전달된다.업데이트 최적화에 유용할 수 있다. | |
onSettled | (data: TData, error: TError, variables: TVariables, context?: TContext) => Promise | void | mutation이 성공적으로 fetch하거나 error를 만났을때 실행될 함수promise 가 리턴되면, await 였다가 resolve한다 | |
onSuccess | (data: TData, variables: TVariables, context?: TContext) => Promise | void | mutation이 fetch에 성공하면 그 결과를 인자로 받아서 작동한다.promise 리턴시, await and resolved | |
retry | boolean | number | (failureCount: number, error: TError) => boolean | 0 | false 면 실패시 재시도 안함.true 면 실패마다 무한재시도number 면 숫자만큼 재시도 |
retryDelay | number | (retryAttempt: number, error: TError) => number | 함수면 retryAttemp 는 재시도 횟수이고 리턴한 시간(ms)만큼 지연예시 : attempt => attempt * 1000 | |
useErrorBoundary | undefined | boolean | (error: TError) => boolean | undefined (global query config 에서 useErrorBoundary 로 세팅) | true 면 랜더링도중에 mutation error 를 던지고 가장 가까운 error boundary로 전파한다false 면, 에러바운더리에 에러를 던지는 걸 disable한다.함수 면 에러 를 받아서 error boundary로 그 에러 를 나타낼지 여부를 리턴한다. |
meta | Record<string, unknown> | 세팅하면, mutation cache 엔트리 에 추가정보를 사용할 수 있다. mutation이 사용가능할때 접근할 수 있다.(예를들어 MutationCache 의 onError , onSuccess 함수들 ) |
변수명 | 타입 | default | 설명 |
---|---|---|---|
mutate | (variables?: TVariables, { onSuccess, onSettled, onError }) => void | mutation 함수를 호출하며 variables 를 넘겨준다. 여러 요청을 보낼경우 onSuccess 가 마지막 콜 이후에 작동하게 된다. | |
data | undefined | unknown | undefined | 쿼리에 의해 마지막에 resolve된 데이터값 |
error | null | TError | 쿼리에 대한 에러 오브젝트 | |
isError | boolean | status==="error" 값 | |
isIdle | boolean | status==="idle" 값 | |
isLoading | boolean | status==="loading" 값 | |
isSuccess | boolean | status==="success" 값 | |
mutate | |||
mutateAsync | (variables: TVariables, { onSuccess, onSettled, onError }) => Promise | mutate랑 비슷한데, await할 수 있는 promise를 리턴해줌 | |
reset | () => void | mutation internal state를 삭제함 (즉 초기 state로 mutation을 리셋) | |
status | string | "idle" :mutation함수 작동 전 초기상태 "loading":mutation함수 실행중 "error":마지막 mutation이 에러났는지 "success": 마지막 mutation이 성공했는지 |