2016-02-11 4 views
21

я получаю следующее предупреждениеРеагировать SetState можно только обновить установленный или монтажный компонент

«Предупреждение: SetState (...): Можно только обновить смонтированный или компонент монтажа Это обычно означает, что вы назвали SetState.() на незамонтированном компоненте. Это не-op. Пожалуйста, проверьте код для компонента ContactPage. "

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

Контактная страница компонента:

import React, { Component, PropTypes } from 'react'; 
import AppStore from '../../stores/AppStore'; 
import AppActions from '../../actions/AppActions'; 
import DataContent from './DataContent'; 

const title = 'Contact Us'; 


class ContactPage extends Component { 

    constructor(props) { 
     super(props); 
     this.state = AppStore.getState(); 
     AppActions.getData(); 
    } 

    static contextTypes = { 
    onSetTitle: PropTypes.func.isRequired, 
    }; 

    componentWillMount() { 
    this.context.onSetTitle(title); 
    AppStore.listen(this.onChange.bind(this)); 
} 

componentWillUnmount() { 
    AppStore.unlisten(this.onChange.bind(this)); 
} 

onChange(state) { 
    this.setState(state); 
} 

renderData() { 
    return this.state.data.map((data) => { 
     return (
      <DataContent key={data.id} data={data} /> 
     ) 
    }) 
} 

    render() { 
    return (
     <div className={s.root}> 
     <div className={s.container}> 
      <h1>{title}</h1> 
      <div> 
       { this.renderData() } 
      </div> 
     </div> 
     </div> 
    ); 
} 

} 

export default ContactPage; 

Когда я положил отладчики в на нагрузке странице контактов она попадает componentWillMount(). Когда я покидаю страницу контакта, он попадает в компонентWillUnmount(). Когда я перейду на страницу назад, он снова попадает в состав компонента componentWillMount(), а затем выдает ошибку, когда он попадает в функцию onChange (состояние).

ответ

36

Проблема в том, что слушатель предыдущего экземпляра компонента все еще зарегистрирован. И поскольку предыдущий экземпляр больше не монтируется, вы получаете эту ошибку.

.bind всегда возвращает новый функция. Так что если вы делаете

AppStore.unlisten(this.onChange.bind(this)); 

, то вы пытаетесь удалить слушателя, который не существует (что, конечно, не выполняется). Это делает не удалить слушатель вы зарегистрированный с AppStore.listen(this.onChange.bind(this))


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

this.onChange = this.onChange.bind(this); 

, а затем использовать AppStore.listen(this.onChange) и AppStore.unlisten(this.onChange).

+0

это сработало! Спасибо :) – erichardson30

+3

".bind всегда возвращает новую функцию" .... mind blown !!! – CambridgeMike

+0

Спасибо. Пробовал с ним пару часов. – Avdept

6

Перед изменением установлен компонент проверки состояния.

render() { 
    return (
    <div ref="root" className={s.root}> 
     // ---- 
    </div> 
    )}; 

onChange(state) { 
    if(this.refs.root) { 
    this.setState(state); 
    } 
} 

Я думаю, это поможет вам.

0

В вашем случае добавьте ссылку на свой корень div и проверьте значение ref перед вызовом setState.

Ваш метод onChange должен выглядеть следующим образом:

onChange(state) { 
    this.refs.yourRef ? this.setState(state) : null;  
} 
-1

Я боролся с этим вопросом, а довольно долгое время.

Что было для меня решено, так это сделать, как предлагал @Felix Kling, но также удостовериться, что моя функция обратного вызова была объявлена ​​в классе компонента, иначе вы не сможете использовать префикс this, что, очевидно, было трюком для меня.

Вот пример того, что я имею в виду:

Legal, но не работает

function onChange() { 
    this.setState({ MyState: newState }) 
} 

class MyComponent extends React.Component { 
    constructor(props) { 
    super(props); 
    onChange = onChange.bind(this); 
    } 

    componentDidMount() { 
    window.addEventListener('resize', onChange); 
    } 

    componentWillUnmount() { 
    window.removeEventListener('resize', onChange); 
    } 

    render() { ... } 
} 

Работа

class MyComponent extends React.Component { 
    constructor(props) { 
    super(props); 
    this.onChange = this.onChange.bind(this); 
    } 

    onChange() { 
    this.setState({ MyState: newState }) 
    } 

    componentDidMount() { 
    window.addEventListener('resize', this.onChange); 
    } 

    componentWillUnmount() { 
    window.removeEventListener('resize', this.onChange); 
    } 

    render() { ... } 
} 

Надеется, что это помогает любой перед лицом этой проблемы. :)

Смежные вопросы

 Смежные вопросы