Rendering more than previous render errors on component without using conditional hooks
P粉331849987
P粉331849987 2023-09-09 22:36:14
0
1
591

I have the following component that renders a clickable link for file upload

import { gql, useLazyQuery, useMutation } from '@apollo/client';
import { useEffect, useState } from 'react';
import type FileUpload from '@app/data/models/FileUpload';
import { ExternalLink } from '@app/mcui/components/atoms/business-process/shared/ExternalLink';
import { isNonEmptyString } from '@divvy-homes/utils';

export type Props = {
  uploadId: FileUpload['id'];
};

const FILE_UPLOAD_QUERY = gql`
  query ($id: UUID!) {
    getFileUpload(id: $id) {
      id
      fileName
      url
    }
  }
`;

const SIGN_FILE_MUTATION = gql`
  mutation ($url: String!) {
    signAdminUploadUrl(url: $url)
  }
`;
export const FileUploadLink = ({ uploadId }: Props) => {
  const [fileUrl, setFileUrl] = useState<string>();
  const [fileName, setFileName] = useState<string>();
  const [getFileData] = useLazyQuery<{
    getFileUpload: {
      url: string;
      fileName: string;
    };
  }>(FILE_UPLOAD_QUERY, {
    onError: console.error,
    onCompleted: (data) => {
      setFileName(data.getFileUpload.fileName);
      setFileUrl(data.getFileUpload.url);
    },
    variables: {
      id: uploadId,
    },
  });

  useEffect(() => {
    void getFileData({ variables: { uploadId } });
  }, [getFileData, uploadId]);

  const [createSignedDocumentUrl] = useMutation<{ signAdminUploadUrl: string }>(
    SIGN_FILE_MUTATION,
    {
      onError: console.error,
      onCompleted: (urlData) => {
        const signedUrl = urlData.signAdminUploadUrl;
        window.open(signedUrl, '_blank', 'noreferrer');
      },
    },
  );

  return isNonEmptyString(fileUrl) ? (
    <ExternalLink
      onClick={() => void createSignedDocumentUrl({ variables: { url: fileUrl } })}
      text={fileName ?? ''}
    />
  ) : undefined;
};

Every time I upload a file using this component I get a react error More hooks were rendered than during the last render. . React indicates that the order of hooks has changed as follows

client.js:1 Warning: React has detected a change in the order of Hooks called by BusinessProcessDetails. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
 1. useContext                 useContext
 2. useContext                 useContext
 3. useContext                 useContext
 4. useContext                 useContext
 5. useRef                     useRef
 6. undefined                  useState

Looking at my code, I can't understand why this error occurs. React says it's the first line of the component that calls useState that causes the error, but that makes no sense to me. Calling a reactive hook without a condition causes this, and the first line of the component that throws this error does not match the order in which the hook changed.

I'm using react 18.2.0, typescript 4.9.5

P粉331849987
P粉331849987

reply all(1)
P粉148434742

It turns out that the problem lies in the way the component is called. The parent component rendering FileUploadLink looks like this

export const MyComponent = ({ fileUpload }: MyProps) => {
  const values = [
    {
      label: 'MyLabel',
      value: fileUpload ? FileUploadLink({ uploadId: fileUpload }) : undefined,
    },
  ];

  return (
    <>
      {values.map((l, v) => {
        <div>{l}</div>;
        {
          v;
        }
      })}
    </>
  );
};

The fix is ​​to wrap the component in a tag, i.e.

const values = [
    {
      label: 'MyLabel',
      value: fileUpload ? <FileUploadLink uploadId={fileUpload} /> : undefined,
    },
  ];
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template