简体   繁体   English

在 useCallback 挂钩中使用 Axios 时反应功能组件无限重新渲染?

[英]React functional component re-rendering infinitely when using Axios in useCallback hook?

Here is a file uploading component, everything works at expected, however, when attempting to POST the file using Axios in a useCallback, the ProgressBar component re-renders infinitely if there is an error from Axios.这是一个文件上传组件,一切正常,但是,当尝试在 useCallback 中使用 Axios 发布文件时,如果 Axios 出现错误, ProgressBar组件会无限重新渲染。 If I comment out the Axios post, the component does not re-render infinitely.如果我注释掉 Axios 帖子,组件不会无限重新渲染。 How do I avoid the infinite re-rendering of the ProgressBar component?如何避免ProgressBar组件的无限重新渲染?

import { useState, useCallback, useEffect } from 'react'
import { useDropzone } from 'react-dropzone'
import uuid from 'react-uuid'
import axios from 'axios'

import ProgressBar from './ProgressBar'

const FileUploader = ({ setNotifications }) => {
  const [fileCount, setFileCount] = useState(0)
  const [filesUploaded, setFilesUploaded] = useState([])
  const [progress, setProgress] = useState(0)
  const [uploaded, setUploaded] = useState(false)
  const [exists, setExists] = useState(false)
  const [error, setError] = useState(false)
  
  const onDrop = useCallback(acceptedFiles => {
    acceptedFiles.forEach(file => {
      const reader = new FileReader()
      // console.log(file)
      reader.onloadstart = () => {
        const exists = filesUploaded.find(uploadedFile => uploadedFile.name === file.name)
        
        if (exists) {
          return setNotifications(notifications => {
            return [...notifications, `'${file.name}' has already been uploaded.`]
          })
        }
        // setStart(true)
        return setFilesUploaded(filesUploaded => {
          return [...filesUploaded, file]
        })
      }
      reader.onabort = () => {
        setError(true)
        console.log('file reading was aborted')
      }
      reader.onerror = () => {
        setError(true)
        console.log('file reading has failed')
      }
      reader.onprogress = e => {
        // console.log('loaded', e.loaded)
        // console.log('total', e.total)
        if (e.lengthComputable) {
          setProgress((e.loaded / e.total) * 100)
        }
      }
      reader.onload = async () => {
        // complete
        await axios.post(
          '/api/images',
          {
            file: reader.result
          }
        )
          .then(res => {
            if (res) {
              setUploaded(true)
              if (res === 200) {
                // success
                setExists(false)
              } else if (res === 409) {
                // already exists
                setExists(true)
              }
            }
          })
          .catch(err => {
            setError(true)
            console.error(err)
          })
      }
      reader.readAsArrayBuffer(file)
    })
    
  }, [filesUploaded, setNotifications])

  const { getRootProps, getInputProps } = useDropzone({ onDrop, multiple: true })

  useEffect(() => {
    setFileCount(filesUploaded.length)
   }, [setFileCount, filesUploaded, setNotifications])

  return (
    <div>
      <div className='file-uploader'>
        <div
          className='file-uploader-input'
          {...getRootProps()}
        >
          <input {...getInputProps()} />
          <p>Upload Files</p>
        </div>
      </div>
      <div className='progress-bar-container'>
        {filesUploaded.map(file => {
          return (
            <ProgressBar
              key={uuid()}
              file={file}
              progress={progress}
              uploaded={uploaded}
              exists={exists}
              error={error}
            />
          )
        })}
      </div>
    </div>
  )
}

export default FileUploader

The component re-renders because filesUploaded is modified in the callback each time and is listed as a dependency to the same callback.组件会重新渲染,因为filesUploaded每次在回调中都被修改,并且被列为对同一回调的依赖。 It looks like you wish to terminate the upload if the file already has been updated, but currently you only terminate the loadstart event handler.如果文件已经更新,您似乎希望终止上传,但目前您只终止loadstart事件处理程序。 I suggest you move some of the functionality out from then loadstart event.我建议您从loadstart事件中移出一些功能。

acceptedFiles.forEach(file => {
  const exists = filesUploaded.find(uploadedFile => uploadedFile.name === file.name)
  if (exists) {
    setNotifications(notifications => {
      return [...notifications, `'${file.name}' has already been uploaded.`]
    })
  } else {
    const reader = new FileReader()
    reader.onloadstart = () => {
      return setFilesUploaded(filesUploaded => {
        return [...filesUploaded, file]
      })
    }
    [...]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 React 组件正在无限地重新渲染 - React component is re-rendering infinitely 使用 Axios 和 useState/useEffect 无限重新渲染 React 功能组件? - Infinite Re-rendering of React Functional Component using Axios and useState/useEffect? 组件不会使用“useEffect”钩子在 React 中重新渲染 - Component not re-rendering in React using a 'useEffect' hook React hook form useEffect 不会通过调用另一个组件来重新渲染功能组件 - React hook form useEffect not re-rendering functional component with call to another component 使用 useEffect 挂钩获取数据时,React 组件不会在 URL 参数更改上重新渲染 - React component not re-rendering on URL parameter change when using useEffect hook to fetch data 子组件,无限重渲染 - Child component, infinitely re-rendering 自定义 React 组件(react-hook)不重新渲染 - Custom React component(react-hook) not re-rendering 如何防止在 React 中的功能组件中重新渲染 - How to prevent re-rendering in functional component in React 在 React 功能组件中重新渲染 - 为什么会出现这种行为? - Re-rendering in React functional component - why this behavior? React.map 不在 state 上重新渲染功能组件的变化 - React .map not re-rendering on state change in functional component
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM