简体   繁体   中英

Avoiding ref to be passed to the parent component: ReactJS

I am having a file uploader which is a child component. The state of the files are being maintained in tha App component. I am trying to mock, the upload and failure cases inside App component itself using setInterval . But I am using passing a ref from the child component to the parent callback, just so that I get the latest upload status of a file inside setTimeout. Implementation works just fine, Is there someway where I can do all this, without passing down any ref to the parent component inside callback?

I am able to successfully mock the completion and failure. In the below sandbox, I am hardcoding the file name to "1.txt" so that uploads fail just for that.

Note: Its ok if I have to create any ref's inside App, I just dont want the ref to be part of onFileUpload callback when passed to the App component

Sandbox: https://codesandbox.io/s/updated-file-upload-forked-k59xgo

Inside File Upload

 const timerRef = useRef<ReturnType<typeof setInterval> | undefined>();

  useEffect(() => {
    if (file.active && !file.uploadError) {
      onFileUpload(file, timerRef);
    }
  }, [file.active, file, onFileUpload]);

Inside App

 const onFileUpload = (
    selectedFile: FileType,
    uploadRef: React.MutableRefObject<
      ReturnType<typeof setInterval> | undefined
    >
  ) => {
    pollRef.current = selectedFile;
    if (!uploadRef.current) {
      uploadRef.current = setInterval(() => {
        if (
          pollRef.current?.uploadStatus === 100 ||
          pollRef.current?.uploadError
        ) {
          clearInterval(uploadRef.current);
        }
        const diff: number = Math.random() * 15;
        let currentProgess: number = pollRef.current?.uploadStatus as number;
        setSelectedFiles((prevState: FileType[]) => {
          return prevState.map((currentFile: FileType) => {
            const {
              file: { name: currentFileName },
              uploadStatus: currentFileUploadStatus
            } = currentFile;
            if (currentFileName === selectedFile.file.name) {
              if (
                selectedFile.file.name === "1.pdf" &&
                currentFileUploadStatus > 40
              ) {
                clearInterval(uploadRef.current);
                return {
                  ...currentFile,
                  uploadStatus: 0,
                  isActive: true,
                  uploadError: "Upload Error"
                };
              }
              currentProgess = Math.min(currentFileUploadStatus + diff, 100);
              return {
                ...currentFile,
                uploadStatus: currentProgess
              };
            } else return currentFile;
          });
        });
        return currentProgess;
      }, 60 * Math.floor(Math.random() * 6) + 100);
    }
  };

You already use the file name as key for React.

<ListItem key={file.file.name} className={"file-name"}>

You could also use it as a key for the timeouts.

Effectively, that's what already happens. You rely on React rendering your unique component to get the right timeout reference.

This allows you to remove uploadRef , also from the UploadFile component as it was only used for this timeout.

const fileIntervals = useRef({});
const onFileUpload = ( selectedFile: FileType ) => {
  // ...
  const { name } = selectedFile;
  if (fileIntervals.current[name]) {
    return;
  }
  fileIntervals.current[name] = setInterval( // ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM