Компонент сохранит состояние даже после его размонтирования
Я создаю форму обратной связи с Formik и хочу перейти от компонентов класса к хукам, но сталкиваюсь с упомянутыми трудностями.
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
let timer = null;
useEffect(() => {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
// ...code ommited for brevity
}
Этот эффект успешно работает после отправки моей формы в ожидании ответа сервера. Компонент Feedback является модальным компонентом react-router, если это имеет значение. Однако, если я снова открою это модальное окно, я увижу сообщение об успешном завершении вместо новой формы. В моем return я условно отображаю сообщение об успехе, если feedbackStatus === "success" или форму, которая, в зависимости от ответа сервера, может отображать сообщение об ошибке в противном случае. Мой компонент класса отлично работает с этим кодом:
componentDidUpdate(prevProps) {
const status = this.props.feedbackResponse.status;
if (prevProps.feedbackResponse.status !== status) {
if (status >= 200 && status < 300) {
this.setState({feedbackStatus: "success"});
this.timer = setTimeout(() => {
this.props.history.goBack();
}, 2500);
} else if (status === "pending") {
this.setState({feedbackStatus: "pending"});
} else {
this.setState({feedbackStatus: "error"});
};
}
}
componentWillUnmount() {
clearInterval(this.timer);
}
Ожидаемый результат: повторное открытие этого модального компонента после успешной отправки формы должно отобразить новую форму, но отобразит предыдущий статус отправки. Это заставляет меня думать, что я вообще не размонтирую свой компонент Feedback, но в чем же тогда моя ошибка?





Вышеупомянутое поведение происходит потому, что эффект также запускается при начальном рендеринге, и в этом случае props.feedbackStatus может быть сохранен из предыдущих экземпляров.
Поскольку вы хотите выполнить эффект только при обновлении компонента, вам потребуется остановить выполнение useEffect при начальном рендеринге, что происходит даже при передаче значений в массив зависимостей. Вы можете сделать это с помощью useRef
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
const isInitialRender = useRef(true);
let timer = null;
useEffect(() => {
if (isInitialRender.current === true) {
isInitialRender.current = false;
} else {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
}
Вы можете использовать <Feedback key = {someKey} />.
Это обеспечит создание нового экземпляра компонента Feedback при его повторном открытии, поэтому ваши старые сообщения об успешном/неудачном завершении будут удалены из состояния.