首页 > 解决方案 > 即使 React.memo 返回 true,子组件也会在父组件时重新渲染

问题描述

我有一个嵌套组件,它启动一个上传图片的 HTTP 请求。它显示进度。

const PreviewItem = React.memo(function PreviewItem(props: PreviewItemProps) {
    const {fileObject, handleRemove, classes, onUploadFinished} = props

    const [isLoading, setIsLoading] = useState(false)
    const [completed, setCompleted] = useState(0);

    const cancelTokenSource = axios.CancelToken.source();

    useEffect(() => {
        const data = new FormData();
        data.append('file', fileObject.file);

        const config: AxiosRequestConfig = {
            onUploadProgress: function (progressEvent) {
                const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
                setCompleted(percentCompleted)
            },
            cancelToken: cancelTokenSource.token
        };

        if (!fileObject.isUploaded) {
            setIsLoading(true)
            avantiApi.post<DirectUploadResponse>("images/upload", data, config).then(response => {

                setIsLoading(false)

                if (onUploadFinished) {
                    onUploadFinished(response.data, fileObject)
                }
            }).catch(e => console.log("Upload Error", e))
        }
        return function abortUpload() {
            console.log("Use effect...aborting...")
            cancelTokenSource.cancel("Cancelled")
        }
    }, [fileObject])

    return <> ..... </>
}, function (prevProps: Readonly<PropsWithChildren<PreviewItemProps>>, nextProps: Readonly<PropsWithChildren<PreviewItemProps>>) {
    const areEqual = prevProps.fileObject === nextProps.fileObject
    console.log("Are equal?", areEqual)
    return areEqual
})

我的问题是,即使 React.memo 的propsAreEqual函数返回 true,组件也会重新渲染 - 如果父级重新渲染 - 在上传图像时,会请求重新启动。我错过了一些关于使用的东西React.memo吗?

标签: reactjsreact-hooks

解决方案


文档

React.memo 仅检查 prop 更改。如果你封装在 React.memo 中的函数组件在其实现中有一个 useState 或 useContext Hook,它仍然会在状态或上下文发生变化时重新渲染。

在内部,您应该检查您的 isLoading 状态:

useEffect(() => {
  ...
  if(!fileObject.isUploaded && !isLoading) {
    setIsLoading(true)
    ...
  }
  ...
}, [fileObject, isLoading])

推荐阅读