React Невозможно выполнить обновление состояния React при отключенной ошибке компонента - PullRequest
1 голос
/ 09 апреля 2020

Я сделал форму входа в систему, чтобы при успешном входе в систему сервер отправлял информацию о пользователе (имя, адрес электронной почты, идентификатор) и изменения некоторых состояний страницы соответственно (например, маршрут, объект пользователя), но всякий раз, когда я вхожу, все работает хорошо, но я получаю сообщение об ошибке в консоли:

index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in Login (at App.js:226)

Это действительно смущает меня, потому что приложение все еще работает хорошо, и я уверен, почему я получаю эту ошибку.

приложение. js * render ():

  render() {

    if (this.state.route === 'login') {
      return <Login loadUser={this.loadUser} routeChange={this.routeChange} /> //this is line 226 at app.js

    } else if (this.state.route === 'register') {
      return <Register loadUser={this.loadUser} routeChange={this.routeChange} />

    } else {
      return (
        <div>
          {/* The rest of the app's home components */}
        </div>
      )
    }

логин. js:

    class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email: "",
            password: "",
            loading: false
        }
    }

    handleChange = (e) => {
        this.setState({ [e.target.name]: e.target.value })

    }

    handleClick = () => {

        this.setState({ loading: true })
        fetch('myApi/login', {
            method: 'post',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                email: this.state.email,
                password: this.state.password
            })
        })
            .then(response => response.json())
            .then(user => {
                if (user.id) {
                    this.props.routeChange('home');

                    this.props.loadUser(user);
                    //localStorage.setItem('user', JSON.stringify(user));
                    this.setState({ loading: false })
                }
            })
    }

    render() {
        return (
            <div className="container">
                <div className="row">
                    <div className="col-sm-9 col-md-7 col-lg-5 mx-auto">
                        <div className="card card-signin my-5">
                            <div className="card-body">
                                <h5 className="card-title text-center">Sign In</h5>
                                <form onSubmit={(e) => e.preventDefault()} className="form-signin">
                                    <div className="form-label-group">
                                        <input onChange={this.handleChange} name="email" type="email" id="inputEmail" className="form-control" placeholder="Email address" autoFocus />
                                        <label htmlFor="inputEmail">Email address</label>
                                    </div>
                                    <div className="form-label-group">
                                        <input onChange={this.handleChange} name="password" type="password" id="inputPassword" className="form-control" placeholder="Password" />
                                        <label htmlFor="inputPassword">Password</label>
                                    </div>
                                    <div className="custom-control custom-checkbox mb-3">
                                        <input type="checkbox" className="custom-control-input" id="customCheck1" />
                                        <label className="custom-control-label" htmlFor="customCheck1">Remember password</label>
                                    </div>
                                    <button onClick={this.handleClick} className="btn btn-lg btn-primary btn-block text-uppercase">Sign in</button>
                                    <hr className="my-4" />
                                    <h6 onClick={() => this.props.routeChange('register')} style={{ textAlign: 'center', cursor: 'pointer' }}>Register instead</h6>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

Ответы [ 2 ]

2 голосов
/ 09 апреля 2020

Проблема заключается в этом thenable условии, когда вы устанавливаете состояние после изменения маршрута. Помните, обновления состояния являются асинхронными и происходят перед каждым новым циклом рендеринга.

if (user.id) {
  this.props.routeChange('home');
  this.props.loadUser(user);
  //localStorage.setItem('user', JSON.stringify(user));
  this.setState({ loading: false }) // <-- error since component unmounted!!
}

Удаление состояния загрузки обратно в ложное состояние должно вызывать предупреждение:

if (user.id) {
  this.props.routeChange('home');
  this.props.loadUser(user);
}

РЕДАКТИРОВАТЬ Чтобы действительно исправить это, переместите изменение маршрута в функцию жизненного цикла, чтобы вы могли правильно установить состояние загрузки обратно на false, если вход в систему не работает или пользовательский объект не имеет id собственность.

handleClick = () => {
  this.setState({ loading: true })
  fetch('myApi/login', {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: this.state.email,
      password: this.state.password
    })
  })
    .then(response => response.json())
    .then(user => {
      if (user.id) {
        this.props.loadUser(user);
        this.setState({ user })
      }
    })
    .finally(() => this.setState({ loading: false })); // run this no matter what
}

componentDidUpdate(prevProps, prevState) {
  // check user state condition, if met, change route
  if (/* user condition met */) {
    this.props.routeChange('home');
  }
}
1 голос
/ 09 апреля 2020

Я предполагаю, что проблема на самом деле в вашей функции loadUser. Не могли бы вы поделиться этим? Вы меняете страницу в функции loadUser?

componentDidMount() {
   this.isMounted = true;
}

componentWillUnmount() {
   this.isMounted = false;
}

handleClick = () => {
fetch('myApi/login', {
    method: 'post',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        email: this.state.email,
        password: this.state.password
    })
})
    .then(response => response.json())
    .then(user => {
        if (user.id) {
            if (this.isMounted) this.setState({ this.state..., loading: false });
            if (this.isMounted) this.props.loadUser(user);
            if (this.isMounted) this.props.routeChange('home');
        }
    })
}
...