无法在componentWillMount中设置状态

时间:2016-10-23 03:13:50

标签: javascript reactjs state

我正在创建一个简单的聊天应用程序,我通过axios对数据库进行api调用,返回一组消息对象。当我在componentWillMount中进行axios调用时,我能够获取数据。然后我尝试setState来显示对话。这是代码:

export default class Chat extends Component {
  constructor(props){
    super(props);

    this.state = {
      messages : [],
      message : '',
    };
    this.socket = io('/api/');
    this.onSubmitMessage = this.onSubmitMessage.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
  }

  componentWillMount() {
    axios.get(`api/messages`)
      .then((result) => {
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState({ 
          messages: [ ...messages.content ] 
        })
  })
};

我看过一些关于生命周期功能和设置状态的帖子,看起来我做的是正确的。

再次强调,axios调用工作正常,设置状态不起作用。我仍然看到一个空数组。提前谢谢!

编辑:这是我的问题的解决方案。它被埋在评论中,所以我想我会把它留在这里..

“我发现了这个问题。实际上是我解析数据的方式。在... messages.content上的扩展运算符不起作用,因为messages.content不存在.message [i] .content存在所以我的修复只是传播...消息然后在子组件中我映射对象并解析.content属性。感谢帮助人员!“

2 个答案:

答案 0 :(得分:11)

在您的情况下,由于您在异步回拨中使用setState()

setState()无法正常工作

工作小提琴:https://jsfiddle.net/xytma20g/3/

您正在进行异步API调用。因此,只有在收到数据后才会调用setState。它与componentWillMountcomponentDidMount无关。您需要处理渲染中的空message。当您从API接收数据时,将该数据设置为状态,组件将使用将在渲染中反映的新状态重新呈现。

伪代码:

export default class Chat extends Component {
  constructor(props){
    super(props);

    this.state = {
      messages : [],
      message : '',
    };
    this.socket = io('/api/');
    this.onSubmitMessage = this.onSubmitMessage.bind(this);
    this.onInputChange = this.onInputChange.bind(this);
  }

  componentWillMount() {
    axios.get(`api/messages`)
      .then((result) => {
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState({ 
          messages: [ ...messages.content ] 
        })
  })

  render(){
    if(this.state.messages.length === 0){
     return false //return false or a <Loader/> when you don't have anything in your message[]
    }

   //rest of your render.
  }
}; 

答案 1 :(得分:0)

  

在安装发生之前立即调用componentWillMount()。它   在render()之前调用,因此在此方法中设置状态   不会触发重新渲染。避免引入任何副作用或   此方法中的订阅。 docs

因此,您需要将componentDidMount称为 -

componentDidMount() {
    axios.get(`api/messages`)
      .then((result) => {
        const messages = result.data
        console.log("COMPONENT WILL Mount messages : ", messages);
        this.setState({ 
          messages: [ ...messages.content ] 
        })
  })