从带有回调的 this.setState 调用迁移到 useState 和 useEffect

Posted

技术标签:

【中文标题】从带有回调的 this.setState 调用迁移到 useState 和 useEffect【英文标题】:Migrate from this.setState calls with callback to useState and useEffect 【发布时间】:2020-06-23 11:45:15 【问题描述】:

我已经使用新的 react 钩子将近 4 个月了,这是创建 react 组件的一个很好的调整。目前,我正在尝试从类组件迁移到功能组件并遇到一些问题。 例如,让我们讨论这个案例并比较函数和类组件以更好地理解问题。

class UserInformation extends React.Component 
    state = 
        isBusy: false,
    ;

    updateImage = (uploadedImageData: IUploadImage): void => 
        const imageData = 
            ImageData: base64ToArrayBuffer(uploadedImageData.ImageData.ImageData),
            FileName: uploadedImageData.FileName,
        ;

        this.setState( isBusy: true , () => 
            this.props.updateSettingsUserImage(this.props.selectedUser, imageData)
                .then(() => this.setState( isBusy: false ));
        );
    ;

    deleteImage = (): void => 
        this.setState( isBusy: true , () => 
            this.props.deleteSettingsUserImage(this.props.selectedUser)
                .then(() => this.setState( isBusy: false ));
        );
    ;

    const  selectedUser  = this.props;

    return (
        <BaseInfoCardHeader
           withUploadableAvatar
           style= margin: '0 -12px' 
           name=selectedUser.FullName
           deleteImage=this.deleteImage
           updateImage=this.updateImage
           photopath=selectedUser.Photopath                        
        />
    );


export default UserInformation;

这里是UserInformation的功能组件版本

const UserInformation = (props) => const [isBusy, setIsBusy] = useState(false);

    const updateImage = (uploadedImageData: IUploadImage): void => 
        const imageData = 
            ImageData: base64ToArrayBuffer(uploadedImageData.ImageData.ImageData),
            FileName: uploadedImageData.FileName,
        ;
        setIsBusy(true);
    ;

    const deleteImage = (): void => setIsBusy(true);

    useEffect(() => 
       if (isBusy) 
          updateSettingsUserImage(props.selectedUser, imageData)
             .then(() => setIsBusy(false));
       
    , [isBusy]);

   useEffect(() => 
       if (isBusy) 
          deleteSettingsUserImage(props.selectedUser)
             .then(() => setIsBusy(false));
       
    , [isBusy]);

    const  selectedUser  = this.props;

    return (
        <BaseInfoCardHeader
           withUploadableAvatar
           style= margin: '0 -12px' 
           name=selectedUser.FullName
           deleteImage=this.deleteImage
           updateImage=this.updateImage
           photopath=selectedUser.Photopath                        
        />
    );


export default UserInformation;

我们可以看到,在功能组件内部,无论是触发 updateImage 还是 deleteImage,都将运行 2 个 useEffects 并进行 API 调用。但是在类组件中,API 调用将在 setState 回调中处理,并且只会请求一个 API 调用。 一种选择是为 imageData 添加另一个状态并在其 useEffect 依赖项列表中使用它。但是如果我们没有 imageData 并且一切都依赖于 isBusy 怎么办。处理这种情况的最佳方法是什么?

【问题讨论】:

【参考方案1】:

为什么你甚至需要在这个组件中设置状态?还要注意不要仅仅将类组件转换为功能组件,因为它的新颖性,基于类的组件仍然有它们的位置。但你的例子实际上是一个很好的候选者。

    const UserInformation = (props) => 
        const [isBusy, setBusy] = useState(false)
        const updateImage = async (uploadedImageData: IUploadImage): void => 
            setBusy(true);
            const imageData = 
                ImageData: base64ToArrayBuffer(uploadedImageData.ImageData.ImageData),
                FileName: uploadedImageData.FileName,
            ;
            await updateSettingsUserImage(props.selectedUser, imageData)
            setBusy(false);
        ;

        const deleteImage = async (): void => 
          setBusy(true);
          await deleteSettingsUserImage(props.selectedUser);
          setBusy(false);
        

        const  selectedUser  = props;

        return (
            <BaseInfoCardHeader
               withUploadableAvatar
               style= margin: '0 -12px' 
               name=selectedUser.FullName
               deleteImage=this.deleteImage
               updateImage=this.updateImage
               photopath=selectedUser.Photopath                        
            />
        );
    

    export default UserInformation;

【讨论】:

那么如何使用 isBusy 呢?我需要它在获取时处理动画。 好的,如果您需要isBusy,请查看更新后的答案

以上是关于从带有回调的 this.setState 调用迁移到 useState 和 useEffect的主要内容,如果未能解决你的问题,请参考以下文章

React:如何使用功能性 usestate/useEffect 复制特定的组件类 setstate 回调示例?

根据google places API调用更新状态

即使在 setState 回调中,解构状态也不会更新

在功能组件中使用回调对 setState 进行反应

如何在我的 setState 函数调用中使用变量?

react setState 回调没有更新状态