useEffect 和 useState 不重新渲染 React 组件

时间:2021-06-13 03:11:28

标签: javascript reactjs

我有一个组件,用户可以在其中拖动一些文件并将其存储在状态中。没有进入大部分代码,这就是我所拥有的

  const [files, setFiles] = useState([]);

  useEffect(() => {
    setFiles(getFileList(files, acceptedFiles));
  }, [files, acceptedFiles]);

我正在使用 React Dropzone 包,当用户将文件放入容器时,dropzone 的 acceptedFiles 属性会填充这些文件。在 useEffect 钩子中,我想根据这些新文件设置我的状态 files,即每当用户添加新文件时,我想更新我的状态以包含这些新文件并触发重新渲染。然而,这并没有发生。当我放下一个文件时,没有任何东西被渲染。但是当我删除另一个文件时,第一个文件被渲染,当我添加第三个文件时,第二个文件被渲染等等......我不确定我做错了什么,有什么建议吗?

这是我的组件:

export function Upload() {
  const { acceptedFiles, getRootProps, getInputProps, isDragActive, open } =
    useDropzone({ noClick: true });

  const [files, setFiles] = useState([]);

  useEffect(() => {
    setFiles(getFileList(files, acceptedFiles));
  }, [files, acceptedFiles]);

  const baseContent = (
    <div className={styles.baseContent}>
      <h4 className={styles.uploadText}>{"click to add or drop files here"}</h4>
      <AiOutlineUpload className={styles.icon} />
    </div>
  );

  return (
    <Dropzone getRootProps={getRootProps} isDragActive={isDragActive}>
      {files.length === 0 ? (
        <Clickzone getInputProps={getInputProps} open={open}>
          {baseContent}
        </Clickzone>
      ) : (
        <FileSystem files={files} getInputProps={getInputProps} open={open} />
      )}
    </Dropzone>
  );
}

function getFileList(files, newFiles) {
  var totalSize = getTotalSize(files);
  var count = files.length;

  for (var i = 0; i < newFiles.length; i++) {
    if (count >= constants.MAX_NUM_OF_FILES) break;

    var file = {
      name: newFiles[i].name,
      type: newFiles[i].type,
      size: newFiles[i].size,
    };

    file.name = sanitizeFileName(file.name);
    file.size = convertToMB(file.size);

    if (file.size > constants.MAX_UPLOAD_SIZE) continue;
    totalSize += file.size;
    if (totalSize > constants.MAX_UPLOAD_SIZE) break;
    count++;
    files.push(file);
  }

  return files;
}

1 个答案:

答案 0 :(得分:1)

目前您的 useEffect 正在等待文件和接受的文件运行。这实际上会导致无限循环,因为您更改文件会导致 useEffect 运行然后设置文件。

您应该做的是使用 onDrop 事件并在删除文件后调用该函数。

像这样

export function Upload() {
  const { acceptedFiles, getRootProps, getInputProps, isDragActive, open } =
    useDropzone({ noClick: true });

  const [files, setFiles] = useState([]);

  const baseContent = (
    <div className={styles.baseContent}>
      <h4 className={styles.uploadText}>{"click to add or drop files here"}</h4>
      <AiOutlineUpload className={styles.icon} />
    </div>
  );

  const onDropAccepted = (acceptedFiles) => {
    setFiles(acceptedFiles)
  }

  return (
    <Dropzone getRootProps={getRootProps} isDragActive={isDragActive} onDrop={handleInDropAccepted}>
      {files.length === 0 ? (
        <Clickzone getInputProps={getInputProps} open={open}>
          {baseContent}
        </Clickzone>
      ) : (
        <FileSystem files={files} getInputProps={getInputProps} open={open} />
      )}
    </Dropzone>
  );
}

这是文档的链接,其中显示了您可以添加的所有其他道具,https://react-dropzone.js.org/#!/Dropzone