Предупреждение. Невозможно выполнить обновление состояния React для отключенного компонента после обновления контекста и перенаправить на другую страницу. - PullRequest
2 голосов
/ 08 апреля 2020

У меня возникла проблема, требующая вашей помощи

У меня есть функция changeProfile, которая будет выполняться после onClick в /editpage

const appContext = useContext(AppContext);
const [userLogin, setUserLogin] = appContext.userLogin;
const [userProfile, setUserProfile] = useState<UserProfile>({
    name: userLogin.name,
    ....
});
const changeProfile = e => {
    e.preventDefault();
    post(API)
        .then(() => {
            setUserLogin({
                ...userLogin,
                name: userProfile.name,
            });
            router.push('/mypage');
        })
        .catch(error => {
            setEditError(error[0]);
            window.scrollTo(0, 0);
        });
};

контексте .tsx

const [userLogin, setUserLogin] = useState({
     email: '',
     name: '',
     ....
});

после перенаправления страницы на /mypage консоль записывает предупреждение об ошибке как заголовок и только в первый раз регистрирует предупреждение (если я вернусь к /editpage и changeProfile один больше времени консоль ничего не записывает в /mypage)

Я пытался redirect после setUserLogin сделать, как показано ниже, но это не работает

const changeProfile = e => {
    e.preventDefault();
    post(API)
        .then(() => {
            setUserLogin({
                ...userLogin,
                name: userProfile.name,
            });
        })
        .catch(error => {
            setEditError(error[0]);
            window.scrollTo(0, 0);
        });
};

const firstUpdate = useRef(true);
useLayoutEffect(() => {
    if (firstUpdate.current) {
        firstUpdate.current = false;

        return;
    }
    console.log(userLogin); //already updated
    router.push('/mypage');
}, [userLogin]);

Спасибо за чтение!

PS: проблема может быть решена с помощью

setTimeout(() => {
    router.push('/mypage');
}, 1000);

, но это абсолютно неправильный выбор

1 Ответ

1 голос
/ 08 апреля 2020

Как следует из предупреждения, поскольку ваш код API является асинхронным, если вы слишком быстро перенаправляете со страницы, setState может возникнуть после того, как компонент уже был размонтирован. Что вы можете сделать, это использовать callback аргумент setState (при условии, что вы вызываете setState где-то в функции setUserLogin), чтобы перенаправить после обновление состояния уже завершено .

Редактировать : Вы можете попробовать добавить другую переменную состояния в ваш контекст, чтобы показать, что обновление выполнено, что-то вроде updated: false, а затем с вашим вызовом setUserLogin:

setUserLogin({
    ...userLogin,
    name: userProfile.name,
    updated: true
});

Затем вы можете использовать хук useEffect для проверки этого условия и затем перенаправить:

useEffect(() => {
    if (userLogin.updated) {
        router.push('/mypage');
    }
})

Затем в какой-то момент вам придется сбросить эту переменную на false , Однако теперь, когда я знаю, что ваш setUserLogin исходит от компонента AppContext, я думаю, что проблема в том, что этот компонент отключается, а это не должно быть. Убедитесь, что вы рендерили этот компонент достаточно высоко в дереве компонентов, так что mypage, на который вы перенаправляете, все еще имеет AppContext смонтированный

Edit 2 : хороший подход для предотвращения эта ошибка заключается в добавлении защиты к классу компонента, который отслеживает, смонтирован ли компонент или нет. Примерно так:

class AppContext extends Component {
    _mounted = False;

    componentDidMount() {
        this._mounted = true;
    }

    componentWillUnmount() {
        this._mounted = false;
    }

    ...
}

Затем, когда вы вызываете setState или функцию обновления из useState, вы можете сначала проверить, смонтирован ли компонент перед попыткой обновления:

if (AppContext._mounted) {
    setUserLogin({
        ...userLogin,
        name: userProfile.name,
        updated: true
    });
}

Однако в вашем случае это может помешать обновлению информации, как вы ожидаете, поскольку компонент отключается, поэтому я думаю, что проблема заключается в том, почему компонент отключается

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...