Search code examples
reactjsreact-hooksreact-reduxrtk-query

How to use a query only when parameter is present and use default value otherwise


I want to get data from my backend only when parameters are present on my screen, and I want to have it use default data if the parameter isn't present. Not sure how I can conditionally use query in a component.

This is what my code looks like:

const emptyInfo: NewQuizInfo = {
  title: "",
  timePerQuestion: 3,
}
const [quizInfo, setQuizInfo] = useState<NewQuizInfo|QuizInfo>(emptyInfo);

const [saveQuizInfo, saveQuizInfoStatus] = useSaveQuizInfoMutation();
const quizInfoQuery = useGetQuizInfoQuery(route.params?.quizId);

useEffect(() => {
  if (route.params?.quizId) {
    // TODO: refetch ?
    // assign query result to `quizInfo` ?
  }
}, [route.params]);

My use case is that I'm editing and creating the fields on the same screen. So I would like the same object to contain either the new quiz data if no parameter was sent to the screen, or the quiz retrieved from the backend if a parameter was sent.

The code above doesn't work because parameters (route.params) are optional. I am looking for a way to send the useQueryHook null and get a default object directly instead of request going through the BE.
Looking for something like:

getQuizInfo: builder.query<QuizInfo, QuizId>({
  query: (id) => id?`${id}`:null,
  onQueryNull: () => emptyQuizObject
}),

Is it possible?


Solution

  • You want to use the "lazy" version of the query so that it doesn't attempt to fetch the thing straight away which gives you the level of control you are looking for.

    With the lazy version, you get returned an array of 2 things. The first is a callback which when called with the variables will make the network request. This also returns a promise so you can react to whatever comes back. The second is the usual results object you are used to. Its more similar to the behaviour of the mutation hooks.

    Crucially, unlike the non-lazy version, it doesnt attempt to make the request straight away without you telling it to, which lets you do what you need in the effect.

    const emptyInfo: NewQuizInfo = {
      title: "",
      timePerQuestion: 3,
    }
    const [quizInfo, setQuizInfo] = useState<NewQuizInfo|QuizInfo>(emptyInfo);
    
    const [saveQuizInfo, saveQuizInfoStatus] = useSaveQuizInfoMutation();
    const [getQuizInfo, quizInfoQuery] = useGetQuizInfoLazyQuery();
    
    
    useEffect(() => {
      if (route.params?.quizId) {
        getQuizInfo(route.params?.quizId).then(result => setQuizInfo(result.data))
      }
    }, [route.params]);