T
TanStack2y ago
foreign-sapphire

What is the best practice for using initial data from another query before the query was settled

Hi! I have an expensive query that fetches all todo items and I also have an additional expensive query that fetches the todo of a single item. I would like to fetch all todo items and then use them as initial data for each single query. This will allow me to invalidate a single todo item without invalidating all todo items. Following the blog by tkdodo on initialData I thought that the best approach for this issue is using the initialData option but I mounted the query before all the todo items were fetched so this doesn't help me. https://tkdodo.eu/blog/placeholder-and-initial-data-in-react-query What is the best approach to solve this issue? Should I mount the query only once I have the data from the todo items or perhaps there is a better way using react-query. This is my solution using a useEffect to set the query cache.
export const useTodoItemQuery = ({
id,
projectId,
enabled = true,
}: Props) => {
const [isTodoItemQueryEnabled, setIsTodoItemQueryEnabled] = useState(false)

const queryClient = useQueryClient()
// Fetch all todos
const { data: todoListData, isSuccess: isSuccessTodoList } = useTodoListQuery({
projectId,
enabled: enabled,
})

// Initialize Query cache with data from all todos to prevent fetching for each todo item.
useEffect(() => {
if (isSuccessTodoList && !queryClient.getQueryData(queryKeys.todoList())) {
const todoItem = todoListData?.find((todoItem) => todoItem.id === id)

// We don't want to initialize the cache with undefined data.
if (todoItem) {
queryClient.setQueryData(queryKeys.todoItem({ id: id }), todoItem)
}

setIsTodoItemQueryEnabled(true)
}
}, [isSuccessTodoList, projectId, queryClient, id, todoListData])

return useQuery({
queryKey: queryKeys.todoItem({ id: id }),
queryFn: () => fetchTodoItem({ id: id }),
enabled: isTodoItemQueryEnabled,
})
}
export const useTodoItemQuery = ({
id,
projectId,
enabled = true,
}: Props) => {
const [isTodoItemQueryEnabled, setIsTodoItemQueryEnabled] = useState(false)

const queryClient = useQueryClient()
// Fetch all todos
const { data: todoListData, isSuccess: isSuccessTodoList } = useTodoListQuery({
projectId,
enabled: enabled,
})

// Initialize Query cache with data from all todos to prevent fetching for each todo item.
useEffect(() => {
if (isSuccessTodoList && !queryClient.getQueryData(queryKeys.todoList())) {
const todoItem = todoListData?.find((todoItem) => todoItem.id === id)

// We don't want to initialize the cache with undefined data.
if (todoItem) {
queryClient.setQueryData(queryKeys.todoItem({ id: id }), todoItem)
}

setIsTodoItemQueryEnabled(true)
}
}, [isSuccessTodoList, projectId, queryClient, id, todoListData])

return useQuery({
queryKey: queryKeys.todoItem({ id: id }),
queryFn: () => fetchTodoItem({ id: id }),
enabled: isTodoItemQueryEnabled,
})
}
Placeholder and Initial Data in React Query
Learn about the different possibilities to avoid loading spinners in React Query.
No description
0 Replies
No replies yetBe the first to reply to this messageJoin

Did you find this page helpful?