Home > Software design >  React.js - call useDocument hook conditionally
React.js - call useDocument hook conditionally

Time:04-30

I have the following code in React:

export const useData= (previewMode: boolean) => {
  if (previewMode) {
    let [value_, loading, error]: any = useDocument(
      doc(getFirestore(app), "settings", "content"),
      {
        snapshotListenOptions: { includeMetadataChanges: true },
      },
    );

    const value: any =
      value_?.data() === undefined ? { data: contentFile } : value_.data();

    return { data: value, loading: loading };
  }
  return {data: contentFile, loading: false};
};

contentFile is a static JSON file that

The thing is I keep getting the following error:

src\lib\use-data.tsx
  Line 11:41:  React Hook "useDocument" is called conditionally. React Hooks must be called in the exact same order in every component render  react-hooks/rules-of-hooks

Now I know the rules of react-hooks, but the problem is that I need a condition, without it, the useDocument hook will be always called and we will query the firestore and I don't want that.

I only want to load the document if the previewMode is on, is that possible?

This is how I use this hook: const { value, data } = useData(previewMode);

Thanks in advance

CodePudding user response:

You can't place a hook into a condition. They must be declared top level in the component, because React indexes them based on their order, then you use the declared result inside the condition.

In your case:

export const useData = (previewMode: boolean) => {
  const document = useDocument(
    doc(getFirestore(app), "settings", "content"),
    {
      snapshotListenOptions: { includeMetadataChanges: true },
    }
  );

  if (previewMode) {
    let [value_, loading, error]: any = document;
  }
  /* rest of component */
}

document is now declared regardless of the condition, and React can track it.


If you don't want the firebase document to be called unless it's needed, consider not rendering current component unless previewMode is true. e.g:

{ previewMode && <useData /> }

Which means in your component previewMode is always true, so it can be simplified:

export const useData = (previewMode: boolean) => {
  let [value, loading, error]: any = useDocument(
    doc(getFirestore(app), "settings", "content"),
    {
      snapshotListenOptions: { includeMetadataChanges: true },
    },
  );

  return { data: value.data(), loading };
};
  • Related