简体   繁体   中英

How to use lifeCyle and setState in react?

this is app.js

class App extends Component {
  constructor() {
    super();
    this.state = {
      todo_lists: [
        { id: 1, name: "Hoc React" },
        { id: 2, name: "Hoc HTML" },
        { id: 3, name: "Hoc Jquery" },
        { id: 4, name: "Hoc CSS" }
      ],
      showList : []
    };
  }
  componentDidMount(){
    let {showList, todo_lists} = this.state
  this.setState({
    showList : [...todo_lists]
  })
  console.log(showList)
  }
}

when console.log(showList) on browser it return empty array like this [], clearly I assigned showList: [...todo_lists] in setState. help me

Issue:

// this.setState is async method
this.setState({
    showList : [...todo_lists]
}); 
console.log(showList) // <--- this will not give you updated value right after

you can use this.setState callback method for that, it is being called right after the state is set

this.setState({
    // showList : [...todo_lists]
    showList : this.state.todo_lists.map(todo => ({ ...todo}))
},() => {
    console.log(this.state.showList) //<------ Check here
})

Suggestion:

constructor() {
    super();
    this.todos = [
        { id: 1, name: "Hoc React" },
        { id: 2, name: "Hoc HTML" },
        { id: 3, name: "Hoc Jquery" },
        { id: 4, name: "Hoc CSS" }
    ]
    this.state = {
      todo_lists: this.todos.map(todo => ({ ...todo})),
      showList : this.todos.map(todo => ({...todo}))
    };
}

From Reactjs.org

Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.

https://reactjs.org/docs/react-component.html#setstate

So what you wrote will NOT happen immediately, and your console.log will NOT get the right values immediately afterwards.

The problem here is that React's setState is an async method, so it may delay the update in favor of perceived improvement in performance.

What you could do, is something like this (if you don't want to use the callback provided by the setState) :

componentDidMount() {

  const {showList, todo_lists} = this.state,
    nextShowList = [...todo_lists];

  this.setState({
    showList: nextShowList
  });

  console.log(nextShowList); // executes immediatelly

}

If you want to use the callback provided by the setState method, simply use it like this:

componentDidMount() {

   const {showList, todo_lists} = this.state;

   this.setState({
     showList: [...todo_lists]
   }, () => console.log(this.state.showList)); // MAY NOT execute immediately

}

Also, as an additional tip (if I may), use the first argument as a function, or you may have problems setting your todo_list!

componentDidMount() {

  this.setState(prevState => {

    return {
      showList: [...prevState.todo_lists]
    };

  }, () => console.log(this.state.showList));

}

Again, for the same reason: Since setState is async, you can't guarantee that the this.state outside of the setState is up-to-date!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM