为什么 useEffect 对父级状态的更改没有发生在子级中?
Why is the useEffect changes to state in the Parent not happening in the Child?
下面是一个 FileUploader 组件(父组件),它在添加文件时呈现 ProgressBar 的(子组件)。我打算传入 FileReader onprogress,以便进度条的宽度从 0 变为 100。为了测试,我制作了一个从 0 到 100 的 useEffect 计数器。我已经确认计数器状态正在更新 console.logging useEffect 中的计数器,但是 ProgressBar 组件中的进度状态未更改,仅发送初始 0。如何将计数器状态传递给 ProgressBar 子级,使其从 0 变为 100?
import { useState, useCallback, useEffect } from 'react'
import { useDropzone } from 'react-dropzone'
const ProgressBar = ({ exists, file, progress }) => {
// only the first value, 0, of progress comes through, why not through 100?
console.log(progress)
return (
<div className='progress-bar-component'>
<div className='progress-bar-filename'>
<span>{ file.name }</span>
</div>
<div className='progress-bar-group'>
<div
className={ `progress-bar${exists.length ? ' progress-bar-exists' : ''}` }
style={ { width: `${progress}%` } }
>
</div>
<div className='progress-bar-percent'>
<span>{ exists.length ? 'Already uploaded' : `${progress}%` }</span>
</div>
</div>
</div>
)
}
const ProgressBars = ({ progressBars }) => {
return (
<div className='progress-bar-container'>
{progressBars}
</div>
)
}
const FileUploader = () => {
const [filesUploaded, setFilesUploaded] = useState([])
const [progressBars, setProgressBars] = useState([])
//
const [counter, setCounter] = useState(0)
const [start, setStart] = useState(false)
useEffect(() => {
if (start) {
const timer = counter < 100 &&
setInterval(() => {
setCounter(counter + 1)
}, 500)
return () => clearInterval(timer)
}
}, [counter, start])
//
const onDrop = useCallback(acceptedFiles => {
acceptedFiles.forEach(file => {
const reader = new FileReader()
reader.onloadstart = () => {
return setFilesUploaded(filesUploaded => {
return [...filesUploaded, file]
})
}
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onprogress = () => {
setStart(true)
return setProgressBars(progressBars => {
return [
...progressBars,
<ProgressBar
key={progressBars.length}
file={file}
exists={filesUploaded}
progress={counter}
/>
]
})
}
reader.onload = () => {
}
reader.readAsArrayBuffer(file)
})
}, [filesUploaded, setStart, counter])
const { getRootProps, getInputProps } = useDropzone({ onDrop, multiple: true })
return (
<div>
<div className='file-uploader'>
<div
className='file-uploader-input'
{...getRootProps()}
>
<input {...getInputProps()} />
<p>Upload Files</p>
</div>
</div>
<ProgressBars progressBars={progressBars} />
</div>
)
}
export default FileUploader
您正在回调内部调用,useEffect 不会影响该回调的呈现。尝试在回调外部调用,在父组件的 return 部分
像这样:
return (
<div>
<div className='file-uploader'>
<div
className='file-uploader-input'
{...getRootProps()}
>
<input {...getInputProps()} />
<p>Upload Files</p>
</div>
</div>
<ProgressBar
key={progressBars.length}
file={file}
exists={filesUploaded}
progress={counter}
/>
<ProgressBars progressBars={progressBars} />
</div>
下面是一个 FileUploader 组件(父组件),它在添加文件时呈现 ProgressBar 的(子组件)。我打算传入 FileReader onprogress,以便进度条的宽度从 0 变为 100。为了测试,我制作了一个从 0 到 100 的 useEffect 计数器。我已经确认计数器状态正在更新 console.logging useEffect 中的计数器,但是 ProgressBar 组件中的进度状态未更改,仅发送初始 0。如何将计数器状态传递给 ProgressBar 子级,使其从 0 变为 100?
import { useState, useCallback, useEffect } from 'react'
import { useDropzone } from 'react-dropzone'
const ProgressBar = ({ exists, file, progress }) => {
// only the first value, 0, of progress comes through, why not through 100?
console.log(progress)
return (
<div className='progress-bar-component'>
<div className='progress-bar-filename'>
<span>{ file.name }</span>
</div>
<div className='progress-bar-group'>
<div
className={ `progress-bar${exists.length ? ' progress-bar-exists' : ''}` }
style={ { width: `${progress}%` } }
>
</div>
<div className='progress-bar-percent'>
<span>{ exists.length ? 'Already uploaded' : `${progress}%` }</span>
</div>
</div>
</div>
)
}
const ProgressBars = ({ progressBars }) => {
return (
<div className='progress-bar-container'>
{progressBars}
</div>
)
}
const FileUploader = () => {
const [filesUploaded, setFilesUploaded] = useState([])
const [progressBars, setProgressBars] = useState([])
//
const [counter, setCounter] = useState(0)
const [start, setStart] = useState(false)
useEffect(() => {
if (start) {
const timer = counter < 100 &&
setInterval(() => {
setCounter(counter + 1)
}, 500)
return () => clearInterval(timer)
}
}, [counter, start])
//
const onDrop = useCallback(acceptedFiles => {
acceptedFiles.forEach(file => {
const reader = new FileReader()
reader.onloadstart = () => {
return setFilesUploaded(filesUploaded => {
return [...filesUploaded, file]
})
}
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onprogress = () => {
setStart(true)
return setProgressBars(progressBars => {
return [
...progressBars,
<ProgressBar
key={progressBars.length}
file={file}
exists={filesUploaded}
progress={counter}
/>
]
})
}
reader.onload = () => {
}
reader.readAsArrayBuffer(file)
})
}, [filesUploaded, setStart, counter])
const { getRootProps, getInputProps } = useDropzone({ onDrop, multiple: true })
return (
<div>
<div className='file-uploader'>
<div
className='file-uploader-input'
{...getRootProps()}
>
<input {...getInputProps()} />
<p>Upload Files</p>
</div>
</div>
<ProgressBars progressBars={progressBars} />
</div>
)
}
export default FileUploader
您正在回调内部调用,useEffect 不会影响该回调的呈现。尝试在回调外部调用,在父组件的 return 部分
像这样:
return (
<div>
<div className='file-uploader'>
<div
className='file-uploader-input'
{...getRootProps()}
>
<input {...getInputProps()} />
<p>Upload Files</p>
</div>
</div>
<ProgressBar
key={progressBars.length}
file={file}
exists={filesUploaded}
progress={counter}
/>
<ProgressBars progressBars={progressBars} />
</div>