queryFn
은 Query를 사용하기 위해 전달되는 함수입니다.
사용자가 Promise를 반환할 것으로 예상하고, 결과 데이터는 query cache로 전환됩니다.
const fetchTodos = async (): Promise<Todos> => {
const response = await axios.get('todos')
const data: Todos = response.data
return data.map((todo) => todo.name.toUpperCase())
}
export const useTodosQuery = () => useQuery(['todos'], fetchTodos)
Custom Hook을 작성하여 쉽게 관리하기
➡ Custom Hook에서 데이터 변환과 결합할 수 있는 추가 로직이 있는 경우 좋은 옵션입니다.
const fetchTodos = async (): Promise<Todos> => {
const response = await axios.get('todos')
return response.data
}
export const useTodosQuery = () => {
const queryInfo = useQuery(['todos'], fetchTodos)
return {
...queryInfo,
data: queryInfo.data?.map((todo) => todo.name.toUpperCase()),
}
}
🚨 fetch
함수마다 실행되며 실제 모든 render에서 실행됩니다.
useMemo
를 사용하여 최적화 할 수 있습니다.optional chaining(?)
을 사용해야합니다.export const useTodosQuery = () => {
const queryInfo = useQuery(['todos'], fetchTodos)
return {
...queryInfo,
// 🚨 don't do this - the useMemo does nothing at all here!
data: React.useMemo(
() => queryInfo.data?.map((todo) => todo.name.toUpperCase()),
[queryInfo]
),
// ✅ correctly memoizes by queryInfo.data
data: React.useMemo(
() => queryInfo.data?.map((todo) => todo.name.toUpperCase()),
[queryInfo.data]
),
}
}
데이터 변환에도 사용할 수 있는 built-in 선택자(select)가 있습니다.
export const useTodosQuery = () =>
useQuery(['todos'], fetchTodos, {
select: (data) => data.map((todo) => todo.name.toUpperCase()),
})
선택자 함수 ID가 변경되기 때문에 모든 render
에서 실행됩니다.
💡 변환 비용이 많이 드는 경우 useCallback
을 사용하거나 안정적인 함수로 참조 분리를 할 수 있습니다.
const transformTodoNames = (data: Todos) =>
data.map((todo) => todo.name.toUpperCase())
export const useTodosQuery = () =>
useQuery(['todos'], fetchTodos, {
// ✅ uses a stable function reference
select: transformTodoNames,
})
export const useTodosQuery = () =>
useQuery(['todos'], fetchTodos, {
// ✅ memoizes with useCallback
select: useCallback(
(data: Todos) => data.map((todo) => todo.name.toUpperCase()),
[]
),
})
💡 select
옵션을 사용하여 데이터 일부만 구독할 수 있습니다.
export const useTodosQuery = (select) =>
useQuery(['todos'], fetchTodos, { select })
// useSelector
export const useTodosCount = () => useTodosQuery((data) => data.length)
export const useTodo = (id) =>
useTodosQuery((data) => data.find((todo) => todo.id === id))
useTodosQuery 에 Custom Select를 전달하여 useSelector
를 만들 수 있습니다.
Dom
은 다시 render되지 않습니다.observer
에 알리지 않도록 선택할 수 있습니다.참조