React component not rerendering after state change despite using setState()

Tags: , , ,



I tried to fetch data from an embedded sqlite db and displayed it in list format. The fetchData() function is working, with correct returned result. However, when I used setState() to update the state, react did not re-render. Next I tried to setState() with array [‘a’,’b’,’c’] at componentDidMount(). React did re-render and showed a, b, c.

import React from 'react';
import sqlite3 from 'sqlite3';


type MyProps = {  };
type MyState = { data: Array<string> };

class App extends React.Component<MyProps, MyState>{
  constructor(props) {
    super(props);
    this.state = { data: [] };
    
  }

  async fetchData(){
    var db = new sqlite3.Database({$DB_PATH});
    var res: string[] = [];
    await db.each('select * from table', [], (err, row) => { //selecting 10 rows from table
      if (err) {
        throw err;
      }
        res.push(row.name);
    });
    db.close();
    console.log(this.state.data) //array length = 0
    this.setState({data: res})
    console.log(this.state.data) //array length = 10
  }

   async componentDidMount() {
      await this.fetchData();   
  }

  render() {
  return (
     <div>
        <ul>
          {this.state.data.map(el => (
            <li>
              {el}
            </li>
          ))}
        </ul>
    </div>
  );
  }
}
export default App;

Answer

Because of db.each won’t return a Promise so that you cannot reach result by ‘await’ statement. Refer to the APIs, you’ll need to this:

each(sql: string, params: any, callback?: (this: Statement, err: Error | null, row: any) => void, complete?: (err: Error | null, count: number) => void): this;

so, you should access the result in the complete callback, code like so:

async fetchData() {
  const db = new sqlite3.Database({ $DB_PATH });
  const res: string[] = [];
  await db.each('select * from table', [], (err, row) => { // selecting 10 rows from table
    if (err) {
      throw err;
    }
    res.push(row.name);
  }, () => {
    console.log(this.state.data) // array length = 0
    this.setState({ data: res })
    console.log(this.state.data) // array length = 10
    db.close();
  });
}

Hope it will be helpful.


Besides, you can also have a try with Statement#all([param, ...], [callback]) function which is a better than each.



Source: stackoverflow