AhmAch
AhmAch

Reputation: 105

setState for an array of objects in handleChange is not working

I au using elasticsearch to do searching in my view (ReactJs). I created a function handleChange to change the state of the data in the table according to what I am searching. so I did this so far in my code :

var esClient = new elasticsearch.Client({
  host: 'localhost:9200',
  log: 'info'
});

class MesExtraits extends Component {

  constructor() {
    super();
    this.state = {
      MP3info: [],
      searchText: '',
    }
  }

  updateSearch = (evt) => {
    this.setState({ searchText: evt.target.value, });
    var searchQ = evt.target.value;
    var search_queryES = "titre:" + searchQ + "*"

    esClient.search({
      q: search_queryES
    }).then(function (body) {
      this.setState({ MP3info: body.hits.hits.map(i => i._source) })

      console.log(this.state.MP3info)

      console.log(body.hits.hits.map(i => i._source))

    }.bind(this), function (error) {
      console.trace(error.message);
    });
  };

  render() {

    const { MP3info } = this.state;
    return (

      <div>
        <SearchBox styleName="gx-d-none gx-d-lg-block gx-lt-icon-search-bar-lg"
          placeholder="Search in app..."
          onChange={this.updateSearch.bind(this)}
          value={this.state.searchText}
        />
        <Paper className={classes.root}>
          <Table className={classes.table} aria-label="simple table">
            <TableHead>
              <TableRow>
                <TableCell><IntlMessages id="MP3.titre" /></TableCell>
                <TableCell align="left"><IntlMessages id="MP3.descfiption" /></TableCell>
                <TableCell align="left"><IntlMessages id="MP3.langue" /></TableCell>
                <TableCell align="left"><IntlMessages id="MP3.stats" /></TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {MP3info.map(row => (
                <TableRow key={row.titre}>
                  <TableCell component="th" scope="row">
                    {row.titre}
                  </TableCell>
                  <TableCell align="left">{row.description}</TableCell>
                  <TableCell align="left">{row.langue}</TableCell>
                  <TableCell align="left"> <span id={row.idMedia} onClick={this.onClickPoup}><i class="icon icon-chart" /> </span> </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </Paper>
      </div>
    );
  }
}

The problem is when I console.log(this.state.MP3info) after setState for MP3info it is not changing. Any help would be appreciated.

Upvotes: 2

Views: 45

Answers (2)

Ayesha Iftikhar
Ayesha Iftikhar

Reputation: 1178

After calling setState, you cannot expect the state to be updated immediately since setState is an asynchronous operation.

However, there is an optional 2nd parameter of a callback function which you can use in setState, if you want to do something immediately after updating the state.

this.setState({
        value: newStateValue,
    }, () => {
     const { value } = this.state; // access the updated value here
    })

Please follow this beautiful explanation of how setState works! link

Also:

When not to use the callback:

React docs recommend that you use the lifecycle events.

Here’s why.

PureComponent and shouldComponentUpdate can be used to tune up a component’s performance. They work by preventing lifecycle methods from firing when props and state haven’t changed.

The setState callback fires regardless of what shouldComponentUpdate returns. So, the setState callback will fire, even when state hasn’t changed.

So.. Don’t be afraid to use the setState callback. It’s there for a reason. But when you do, keep an eye on shouldComponentUpdate, if you see any shiftiness.

Upvotes: 2

ronen
ronen

Reputation: 1490

setState is asynchronous. so it will work like this:

this.setState({ MP3info: body.hits.hits.map(i => i._source) }, () => {
    console.log(this.state.MP3info)
})

from documentation:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied.

Upvotes: 4

Related Questions