2

I've been using the useMutation() hook for crud tasks for my app, and I feel that I'm writing a lot of repeated code, initially my code was like this:

const [createList] = useCreateList(reset, err => setError(err.message));
const [updateList] = useCreateList(reset, err => setError(err.message));
const [deleteList] = useCreateList(reset, err => setError(err.message));

Where the reset function is this:

const reset = () => {
    setQsButtonStatus(null); 
    setSelectedList(null);
    setTitleValue("");
}

The desired end code I would want is this:

const {createList, updateList, deleteList} = useListMutation(reset, err => setError(err.message))

I can make this work but to me the code for it looks very messy (again a lot of repeated code):

import * as List from "./list-api";

const useListMutation = (onSettled, onError) => {

    const [createList] = useMutation(List.createList, {
        onMutate: (listTitle) => {
            queryCache.cancelQueries("lists");
            const current = queryCache.getQueryData("lists");
            queryCache.setQueryData("lists", prev => [...prev, {title: listTitle, id: uuidv4()}])
            return () => queryCache.setQueryData("lists", current);
        },
        onError: (err, variables, rollback) => {rollback(); onError(err)},
        onSettled: () => {
            queryCache.invalidateQueries("lists");
            onSettled();
        }
    })

    const [updateList] = useMutation(List.updateList, {
        onMutate: ({id, titleValue}) => {
            queryCache.cancelQueries("lists");
            const current = queryCache.getQueryData("lists");
            queryCache.setQueryData("lists", prev => [
                ...prev.filter(list => list._id !== id),
                {_id: id, title: titleValue}
            ])
            return () => queryCache.setQueryData("lists", current);
        },
        onError: (err, variables, rollback) => {rollback(); onError(err)},
        onSettled: () => {
            queryCache.invalidateQueries("lists");
            onSettled();
        }
    })

    const [deleteList] = useMutation(List.deleteList, {
        onMutate: (id) => {
            queryCache.cancelQueries("lists");
            const current = queryCache.getQueryData("lists");
            queryCache.setQueryData("lists", prev => [
                ...prev.filter(list => list._id !== id),
            ])
            return () => queryCache.setQueryData("lists", current);
        },
        onError: (err, variables, rollback) => {rollback(); onError(err)},
        onSettled: () => {
            queryCache.invalidateQueries("lists");
            onSettled();
        }
    })


    return {createList, updateList, deleteList};

}

export default useListMutation; 

Is there a better way to do this?

1 Answer 1

1

One way of reducing the duplicated code would be to create a getOptions function which returns the onMutate, onError, and onSettled functions. This would look something like this:

const useListMutation = (onSettled, onError) => {
  const getOptions = (onMutate) => ({
    onMutate(data) {
      queryCache.cancelQueries("lists")
      const current = queryCache.getQueryData("lists")
      onMutate(data)
      return () => queryCache.setQueryData("lists", current)
    },
    onError(err, variables, rollback) {
      rollback()
      onError(err)
    },
    onSettled() {
      queryCache.invalidateQueries("lists")
      onSettled()
    },
  })

  const [createList] = useMutation(
    List.createList,
    getOptions((listTitle) => {
      queryCache.setQueryData("lists", (prev) => [
        ...prev,
        { title: listTitle, id: uuidv4() },
      ])
    })
  )

  const [updateList] = useMutation(
    List.updateList,
    getOptions(({ id, titleValue }) => {
      queryCache.setQueryData("lists", (prev) => [
        ...prev.filter((list) => list._id !== id),
        { _id: id, title: titleValue },
      ])
    })
  )

  ...
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.