0

I'm fetching data from an API call. So on componentWillMount I'm making the API call which is mappedDispatchToProps: fetchCats

class Cats extends Component {

  constructor(props){
    super();
    this.state = {
      toPass: 0
      }
  }


  componentWillMount() {
    this.props.fetchCats(this.state.toPass);
  };



  getCats(){    // <= Is this the proper way to update the state and call the api?

    this.setState({
      toPass: this.state.toPass+2     //<= increment by 2
    });

    this.props.fetchCats(this.state.toPass);
  }

  renData() {
    //map the array this.props.categories and return data
  }


  render(){

    const { categories } = this.props.categories
    console.log("CATEGORIES: ", categories);

    return (
     <View>
      <View>
      <Button
        name="PressMe"
        onPress={() => this.getCats()}>
      </Button>

      </View>
      <View>
        {this.reData()}
      </View>
     </View>
    )
  }

}

So the first time when the page loads toPass = 0. When I click the button, the value passed is 2 but I'm getting the same results for categories. The results are supposed to append to the categories array in the Redux state. But after the first press everything works fine, except have double entries of the results for toPass=0. What is wrong with my getCats() function?

Many thanks.

Somename
  • 3,376
  • 16
  • 42
  • 84
  • Possible duplicate of [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Michael Cheng Sep 22 '17 at 17:59
  • 1
    Just an initial guess having seen similar pieces of code as I assume `this.props.fetchCats(this.state.toPass);` is calling your redux action which does something to `categories`. If so, then `this.state.toPass` is not guaranteed to be updated at the time `fetchCats` is being called. Hence getting a duplicate entry of 0 the first time. Every other time afterwards, you are simply appending the previous result from the previous async action. See the linked duplicate for why and how to fix this. – Michael Cheng Sep 22 '17 at 18:02
  • 1
    One more thing, you can even validate that this is probably the issue by adding `{this.state.toPass}` in your render and you'll see it being eventually updated with the latest value which probably won't match the last value in your `categories` array. – Michael Cheng Sep 22 '17 at 18:06
  • Exactly, I am already doing `{this.state.toPass}` and the value was only showing what it was supposed to be in the previous `onPress`. Many thanks for your time and explanation. – Somename Sep 22 '17 at 18:09

1 Answers1

3

Try this:

  getCats = () => {
    this.setState({
      toPass: this.state.toPass+2
    }, () => {this.props.fetchCats(this.state.toPass)});
  }

and change onPress line with onPress={this.getCats}

blacksun
  • 733
  • 7
  • 24
  • Works like a charm! Many many thanks. So what is the issue here? Why is the way I was calling not working? – Somename Sep 22 '17 at 18:05
  • `setState` is an async call. You were not waiting for the callback to `fetchCats` – Pop-A-Stash Sep 22 '17 at 20:50
  • when you use brackets while you are assigning, you are actually calling the function. And as setState is async, you need to use callback. – blacksun Sep 23 '17 at 06:46