Can't set state in componentWillMount

萝らか妹 提交于 2019-12-18 15:36:06

问题


I am creating a simple chat app where I make an api call to my database via axios which returns an array of message objects. I am able to get the data when I make an axios call in componentWillMount. Then I am trying to setState to display the conversation. Here's the code:

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 ] 
        })
  })
};

I have seen some posts concerning lifecycle functions and setting state, and it seems like I'm doing the right thing.

Again to highlight, axios call working fine, setting the state is not working. I am still seeing an empty array. Thanks in advance!

EDIT: Here is the solution to my issue specifically. It was buried in a comment, so I thought I'd leave it here..

"I discovered the issue. It was actually in how I was parsing my data. The spread operator on ...messages.content didn't work because messages.content doesn't exist. messages[i].content exists. So my fix was to spread just ...messages Then in a child component I map over the objects and parse the .content property. Thanks for the help guys!"


回答1:


In your case, your setState() won't work because you're using setState() inside an async callback

Working Fiddle: https://jsfiddle.net/xytma20g/3/

You're making an API call which is async. So, the setState will be invoke only after receiving the data. It does not do anything with componentWillMount or componentDidMount. You need to handle the empty message in your render. When you receive your data from the API, set that data to the state and component will re-render with the new state which will be reflected in your render.

Pseudo code:

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.
  }
}; 



回答2:


componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state in this method will not trigger a re-rendering. Avoid introducing any side-effects or subscriptions in this method. docs

So, You need to call componentDidMount as-

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


来源:https://stackoverflow.com/questions/40199151/cant-set-state-in-componentwillmount

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!