Выполните миграцию из вызовов this.setState с обратным вызовом для использования useState и useEffect. - PullRequest
0 голосов
/ 11 марта 2020

Я уже использовал новые реактивные крючки в течение почти 4 месяцев, и это отличная настройка для создания реактивных компонентов. В настоящее время я пытаюсь перейти от компонентов класса к функциональным компонентам, и у меня есть некоторые проблемы с этим. Например, давайте обсудим этот случай и сравним компоненты функций и классов, чтобы лучше понять проблему.

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 . Каков наилучший способ справиться с этим видом сценария ios?

1 Ответ

1 голос
/ 11 марта 2020

Зачем вам вообще нужно устанавливать состояние в этом компоненте? Также будьте осторожны, чтобы не просто преобразовать компоненты класса в функциональные компоненты, потому что компоненты на основе классов все еще имеют свое место. Но ваш пример на самом деле хороший кандидат.

    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;
...