3

I want to display list of tables in the database if user presses '+'button and remove the list of tables when '-' button is pressed. My code is:

class DatabaseItem extends Component{
  constructor(){
    super();
    this.state = {
      tabList : [],
      plusIsNext : true
    };
  }

  flagOn(){
    this.setState({
      plusIsNext:!this.state.plusIsNext
    });
  }
  showTables(){
    if(this.state.plusIsNext){
      httpUtil.get(`http://localhost:4553/api?query=
      SELECT * FROM information_schema.tables WHERE table_schema='public'`,this.props.dbname).then(response => {
        this.setState({
          tabList:response.data
        })
      });
    }
    else{
      let arr = [];
      this.state.tabList = [];
      console.log(this.state.tabList);
    }
    this.flagOn();
  }
  render(){
    let sign = this.state.plusIsNext ? '+':'-';
    return(
      <div key ={this.props.dbname} >
        <button onClick ={() => {this.showTables()}}>{sign}</button><a>{this.props.dbname}</a>
        {this.state.tabList.map(table => {
          return(
            <div key = {table.table_name}>{table.table_name}</div>
          );
        })}
      </div>
    );
  }
}

For now I have updated the value of tabList directly by reassigning empty array [] to this.state.tabList and it works. If I press the + button tables of the particular database is shown and if I press the - button the list disappears. But if I use the setState to reassign empty array to tabList, the tabList doesn't get empty.

this.setState({
      tabList:[]
    })

or

let arr = [];
this.setState({
  tabList:arr
});

Am I missing something?

2 Answers 2

2

I think your issue was the flagOn call. Because JS is asynchronous, it is best not to call setState more than once at a time. What happens is it calls the http request, jumps to the flagOn and calls setState, then comes back to request once its complete and setState once again.

I refactored your code by consolidating these calls into your conditional. If I understood your code flow properly, this should work!

class DatabaseItem extends Component{
  constructor(){
    super();
    this.state = {
      tabList : [],
      plusIsNext : true
    };

    this.showTables = this.showTables.bind(this)
  }

  showTables(){
    if (this.state.plusIsNext) {
      httpUtil.get(`http://localhost:4553/api?query=
      SELECT * FROM information_schema.tables WHERE table_schema='public'`,this.props.dbname).then(response => {
        this.setState({ 
          tabList: response.data,
          plusIsNext: false
        })
      });
    } else {
      this.setState({ 
        tabList: [],
        plusIsNext: true
      })
    }
  }

  render(){
    let sign = this.state.plusIsNext ? '+':'-';
    return(
      <div key ={this.props.dbname} >
        <button onClick={this.showTables}>{sign}</button><a>{this.props.dbname}</a>
        {this.state.tabList.map(table => {
          return(
            <div key = {table.table_name}>{table.table_name}</div>
          );
        })}
      </div>
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I get it now. This fixed my problem.
-1

I guess you should call setState once only, after you have fetched the data or empty list:

*showTables(){
  let _tabList = []
  let _plusNext = true

    if (this.state.plusIsNext) {
      yield httpUtil.get(`http://localhost:4553/api?query=
      SELECT * FROM information_schema.tables WHERE table_schema='public'`,this.props.dbname).then(response => {

          _tabList = response.data
          _plusNext = false
      });
    } 

    yield this.setState({ tabList: _tabList, plusIsNext: _plusNext})
  }

Edit: Converted the function to generator function.

5 Comments

I saw what was wrong with my code. corrected it. ( : instead of = )
There is a problem with your code. The httpUtil.get is asynchronous. That means when this.setState is called, httpUtil.get might have not returned (or even have not been executed).
Thanks @WinChiu. I have edited my code. Hopefully it should work now
what does yield do? and wont removing the else condition cause the setState below to get executed regardless of the valuse of plusIsNext?
I wrote a generator function. yield make sure to complete the execution before next yield, thus works as synchronous execution. If I look at your code, you are calling setState at both place - if and else. What I did it is, defined the variables and values which you are doing in else condition. If, if condition is true, your tabList and plusIsNext will be having values, otherwise the state will have empty tab list and false (as same as else condition)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.