【问题标题】:Fix "Can't perform a React state update on an unmounted component" error修复“无法在未安装的组件上执行 React 状态更新”错误
【发布时间】:2019-06-15 06:51:03
【问题描述】:

当我尝试在我的 Web 应用程序中推送到新页面时,以下代码会出现控制台错误:

警告:无法对未安装的组件执行 React 状态更新。 这是一个空操作,但它表明您的应用程序中存在内存泄漏。 要修复,请取消 useEffect 中的所有订阅和异步任务 清理功能。 在 PasswordResetPage(由 Context.Consumer 创建)

您会在注释掉的代码中注意到我尝试使用useEffect,因为这是大多数stackoverflow 答案所指向的。但是,错误仍然存​​在。如何在这种情况下使用history.push 并摆脱错误?

import React, { useState /* , useEffect */ } from 'react'
import useForm from 'react-hook-form'
import Logo from '../assets/images/logo-icon-orange.png'
import TextInput from '../components/TextInput'
import Footer from '../components/Footer'
import AnimatedButton from '../components/AnimatedButton'
import logger from '../logger'
import { sleep } from '../utils/promise'
import PasswordResetSchema from './validation/PasswordResetSchema'

const PasswordResetPage = ({ history }) => {
  const [isSubmitting, setSubmitting] = useState(false)
  // const [isDone, setDone] = useState(false)
  const { register, handleSubmit, errors } = useForm({
    validationSchema: PasswordResetSchema,
  })

  const onSubmit = async data => {
    setSubmitting(true)
    await sleep(2000)
    logger.info('form data', data)
    // setDone(true)
    history.push('/confirmation')
  }

  // useEffect(() => {
  //   if (isDone) {
  //     history.push('/confirmation')
  //   }
  // })


  return (
    <form onSubmit={handleSubmit(onSubmit)} noValidate>
      <div className="text-center mb-4">
        <img className="mb-4" src={Logo} alt="Striver" width={72} />
        <h1 className="h3 mb-3 font-weight-normal">Password reset</h1>
        <p>Enter your email address below and we will send you instructions on how you can reset your password.</p>
      </div>

      <div className="form-label-group">
        <TextInput type="email" id="email" register={register} label="Email address" errors={errors} />
      </div>

      <AnimatedButton actionTitle="Next" isSubmitting={isSubmitting} />
      <Footer />
    </form>
  )
}

export default PasswordResetPage

【问题讨论】:

标签: javascript reactjs react-hooks


【解决方案1】:

看看这是否适合你:

带有工作示例的代码沙盒:

https://codesandbox.io/s/reactrouteranswerso-817bp

const onSubmit = async data => {
    setSubmitting(true)
    await sleep(2000)
    logger.info('form data', data)
    setDone(true)
  }

  useEffect(() => {
    if (isDone) {
      history.push('/confirmation')
    }
  },[isDone]);

CodeSandbox 上的工作代码:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

import "./styles.css";

function App() {
  const [user, setUser] = useState(null);

  function doLogin() {
    console.log("Inside do login...");
    setUser("someUserID");
  }

  function doLogout() {
    console.log("Inside do logout...");
    setUser(null);
  }

  return (
    <Router>
      <AllRoutes user={user} doLogin={doLogin} doLogout={doLogout} />
    </Router>
  );
}

function AllRoutes(props) {
  console.log("Rendergin AllRoutes...");
  // console.log(props);
  return (
    <Switch>
      <Route exact path="/" component={Component1} />
      <Route exact path="/comp2" component={Component2} />
    </Switch>
  );
}

function Component1(props) {
  const [isDone, setIsDone] = useState(false);

  useEffect(() => {
    if (isDone) {
      props.history.push("/comp2");
    }
  }, [isDone, props.history]);

  return (
    <React.Fragment>
      <div>Component1</div>
      <button onClick={() => setIsDone(true)}>Submit</button>
    </React.Fragment>
  );
}

function Component2(props) {
  const [goBack, setGoBack] = useState(false);

  useEffect(() => {
    if (goBack) {
      props.history.push("/");
    }
  }, [goBack, props.history]);

  return (
    <React.Fragment>
      <div>Component2</div>
      <button onClick={() => setGoBack(true)}>Go Back</button>
    </React.Fragment>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【讨论】:

  • 由于完整性,我已经接受了这个作为答案,但是,根本原因在于我正在使用的表单库。干杯!
  • @AndreGallo 我也在使用 react-hook-form 并通过重置来解决这个问题。你是怎么解决的?
  • @Shay 我当时更新到最新版本
  • @AndreGallo 谢谢,这并没有为我解决。但至少这消除了一种可能性。
【解决方案2】:

我相信await sleep(2000) 是实际 API 调用的替代品。
API 调用以及history.push 是副作用,因此应该放在useEffect 中。
试试这个:

const PasswordResetPage = ({ history }) => {
  const [formData, setFormData] = useState(null);

  // ...

  const onSubmit = async data => {
    setFormData(data);
  }

  useEffect(() => {
    logger.info('form data', formData);
    sleep(2000).then(() => history.push('/confirmation'););
  }, [formData]);

  // ...
}

【讨论】:

    猜你喜欢
    • 2019-10-05
    • 2023-02-11
    • 2022-10-04
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2021-11-30
    相关资源
    最近更新 更多