Реагировать на текст мутации запроса

Я просто играю с реактивным запросом

с машинописным текстом

Я имею в виду, что делаю свои первые попытки

Это правильный путь?

const useCreateTodo = () => {
  const queryClient = useQueryClient();
  return useMutation(
    (todo: TodoDto) => axios.post(`${URL}/todos`, todo).then((res) => res.data),
    {
      onMutate: async (newTodo: TodoDto) => {
        // Cancel any outgoing refetches (so they don't overwrite our optimistic update)
        await queryClient.cancelQueries("todos");

        // Snapshot the previous value
        const previousTodos = queryClient.getQueryData("todos");

        // Optimistically update to the new value
        queryClient.setQueryData<TodoDto[] | undefined>("todos", (old) =>
          old ? [...old, newTodo] : old
        );

        // Return a context object with the snapshotted value
        return { previousTodos };
      },
      // If the mutation fails, use the context returned from onMutate to roll back
      onError: (
        err,
        newTodo,
        context:
          | {
              previousTodos: unknown;
            }
          | undefined
      ) => {
        queryClient.setQueryData(
          "todos",
          context ? context.previousTodos : context
        );
      },
      // Always refetch after error or success:
      onSettled: () => {
        queryClient.invalidateQueries("todos");
      },
    }
  );
};

person user3887366    schedule 17.01.2021    source источник


Ответы (1)


оптимистичные обновления немного сложны для вывода типов. Теперь в документации есть пример для этого случая .

Из этого примера:

const addTodoMutation = useMutation(
    newTodo => axios.post('/api/data', { text: newTodo }),
    {
      // When mutate is called:
      onMutate: async (newTodo: string) => {
        setText('')
        // Cancel any outgoing refetches (so they don't overwrite our optimistic update)
        await queryClient.cancelQueries('todos')

        // Snapshot the previous value
        const previousTodos = queryClient.getQueryData<Todos>('todos')

        // Optimistically update to the new value
        if (previousTodos) {
          queryClient.setQueryData<Todos>('todos', {
            ...previousTodos,
            items: [
              ...previousTodos.items,
              { id: Math.random().toString(), text: newTodo },
            ],
          })
        }

        return { previousTodos }
      },
      // If the mutation fails, use the context returned from onMutate to roll back
      onError: (err, variables, context) => {
        if (context?.previousTodos) {
          queryClient.setQueryData<Todos>('todos', context.previousTodos)
        }
      },
      // Always refetch after error or success:
      onSettled: () => {
        queryClient.invalidateQueries('todos')
      },
    }
  )

Пара объяснений:

  • По сути, вы хотите установить определение типа только для onMutate, так что вывод типа будет работать для mutateFn (выводится newTodo), а также для контекста в onError.
  • добавьте универсальные шаблоны для getQueryData, чтобы набрать previousTodos. Однако вам не нужно объединяться с undefined - response-query сделает это за вас.
  • функциональное средство обновления для setQueryData сложно, потому что оно требует от вас возврата массива, но old может быть неопределенным. Я предпочитаю использовать previousTodos, возвращенный getQueryData
person TkDodo    schedule 17.01.2021
comment
Можно ли вызвать useQueryClient внутри настраиваемого хука, как это? const useCreateTodo = () = ›{'const queryClient = useQueryClient ();' вернуть useMutation (...); } - person denis_n; 18.06.2021
comment
Да, безусловно. useQueryClient - это просто контекст реакции :) - person TkDodo; 18.06.2021
comment
Разве установка типа на post axios не была бы более полным примером? МутацияFn будет выглядеть так: (newTodo: <Pick<Todo, 'text'>) => axios.post<Todo>('/api/todos', { data: newTodo}) - person p6l-richard; 19.07.2021