#javascript #reactjs
#javascript #reactjs
Вопрос:
Я хочу сохранить пользователя в базе данных Firebase в реальном времени при создании пользователя в форме регистрации. Если я верну функцию Firebase (значение) для сохранения пользователей в .затем обработчик вместо того, чтобы просто вызвать его (без инструкции return), я получаю сообщение об ошибке от React, в котором говорится «Не удается выполнить обновление состояния react для размонтированного компонента».
Мой код для обработчика отправки формы регистрации выглядит примерно следующим образом:
const SignUpFormBase = (props) => {
const [credentials, setCredentials] = useState(INITIAL_STATE);
const [error, setError] = useState(null);
[some other code]
const handleSubmit = (e) => {
firebase
.doCreateUserWithEmailAndPassword(email, passwordOne)
.then(authUser => {
// create a user in the Firebase realtime database
return firebase.database().ref(`users/${authUser.user.uid}`)
.set({ username, email });
})
.then(() => {
setCredentials(INITIAL_STATE);
props.history.push(ROUTES.DASHBOARD);
})
.catch(error => {
setError(error);
});
e.preventDefault();
};
return (
[some jsx]
);
};
const SignUpForm = withRouter(SignUpFormBase);
export default SignUpForm;
Код действительно работает, независимо от того, включаете вы оператор return или нет. Однако, если вы не используете оператор return , предупреждение отображаться не будет.
Я просто не понимаю, почему я получаю вышеупомянутое предупреждение от firebase, поскольку я (по-видимому) не выполняю никаких обновлений состояния компонента после его размонтирования.
Обновить:
Компонент фактически размонтируется до того, как перехватчик setCredentials получит возможность обновить состояние. Это не из-за перехода к истории в приведенном выше коде, а из-за общедоступного маршрута, который я реализовал, чтобы показывать пользователям только страницы, которые им разрешено видеть. Он использует новый перехват useContext, который запускает повторный рендеринг при изменении значения контекста (значение получено из подписки на метод firebase onAuthStateChanged). Я решил проблему, поместив вызов setCredentials в перехват useEffect:
useEffect(() => {
// set credentials to INITIAL_STATE before ComponentDiDUnmount Lifecycle Event
return () => {
setCredentials(INITIAL_STATE);
};
}, []);
Однако я все еще не понимаю, почему отсутствующий оператор return (в предыдущей настройке) приводит к исчезновению предупреждения react.
Комментарии:
1. Можете ли вы поделиться
setCredentials
кодом?2. Это означает, что вы уничтожаете компонент и некоторую часть кода, пытающуюся обновить состояние.
3. @UtsavPatel: обновленный блок кода.
4. Спасибо @andreW . Это решение было решением, которое я искал!
Ответ №1:
Исходя из данного кода, я не уверен, какая часть приводит к предупреждению. Тем не менее, я хотел бы дать несколько советов, которые помогут точно указать на это (сложно написать это ясно в комментарии, поэтому я просто публикую в качестве ответа).
firebasePromise
.then(() => {
// [1] async code
setCredentials(INITIAL_STATE);
// [2] sync code
// UNMOUNT happens after route change
props.history.push(ROUTES.DASHBOARD);
})
.catch(error => {
// [3] async code
setError(error);
});
Я подозреваю, что проблема связана с порядком выполнения кода синхронизации / асинхронности. Две вещи, которые вы можете попробовать, чтобы получить больше информации.
- Проверьте, вызван ли [3], используйте консоль.может быть, войти?
- Оберните [2] в
setTimeout(() => {})
, чтобы тоже сделать его асинхронным.
Моя ставка делается на [3] . каким-то образом после вызова [2] выдается какая-то ошибка.
Ответ №2:
Ваша проблема здесь:
setCredentials(INITIAL_STATE);
props.history.push(ROUTES.DASHBOARD);
скорее всего, setCredentials
это асинхронная функция
и когда он пытается изменить состояние, у вас уже есть другой маршрут из-за props.history.push(ROUTES.DASHBOARD)
в результате у вас нет компонента, и вы не можете обновить состояние
попробуйте:
setCredentials(INITIAL_STATE).then(
props.history.push(ROUTES.DASHBOARD);
)
Комментарии:
1.
setCredential
является установщиком перехвата React, он не возвращает обещание.