Charles Jennings
Charles Jennings

Reputation: 11

setState not working inside axios fetch

class ItemsPage extends React.Component {

  constructor(props)
  {
    super(props)
    this.state = {items: null }
    this.fetchImages = this.fetchImages.bind(this)
  }


  fetchImages()
  {
    var self = this

    axios.get('https://api.instagram.com/v1/users/self/media/recent/?access_token=')
      .then(function (result)  {
        const items = result
        self.setState({ items: 'test' })
      });

  }

  componentDidMount()
  {
    this.fetchImages()
    console.log(this.state.items)
  }

  render () {

    return (

      <div>Test</div>


    );

  }
}

I set items to null and console.log with null still appearing I've tried logging the result and I get my data Im looking for help please! Also have tried using arrow function in es6 still doesn't setState

Upvotes: 1

Views: 4268

Answers (1)

devserkan
devserkan

Reputation: 17638

Let's gather all the comments and suggestions then provide an answer :)

Your main problem, as said in the comments, logging your state in the wrong place. Since setState is asynchronous, right after putting a console.log did not work. Here, you have two options.

First one is using a callback in your setState method.

self.setState({ items: "test" }, () => console.log(this.state.items))

Your second option is using console.log in your render method.

render () {
    console.log( this.state.items );
    return (
    ...

So, in the first render, you see the initial value, after the update you see the data. Remember, never use setState in the render method but logging your state is OK here.

The second problem, not actually a problem but not necessary maybe, you don't need to use var self = this in your function. If you use an arrow function instead of the regular one, you can directly use this there since arrow functions do not create own scopes.

axios.get('https://api.instagram.com/v1/users/self/media/recent/?access_token=')
    .then( result => this.setState({ items: 'test' })
);

So, your whole component would be something like that:

class ItemsPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = { items: null }
    this.fetchImages = this.fetchImages.bind(this)
  }

  fetchImages() {
    axios.get( "https://api.instagram.com/v1/users/self/media/recent/?access_token=" )
      .then(result => this.setState({ items: "test"} )
    );
  }

  componentDidMount() {
    this.fetchImages();
  }

  render() {
    console.log( this.state.items );
    return <div>Test</div>;
  }
}

If you have proper Babel plugins and configuration, you can even use class-fields proposal to simplify your code.

class ItemsPage extends React.Component {
  state = { items: null };

  fetchImages() {
    axios.get( "https://api.instagram.com/v1/users/self/media/recent/?access_token=" )
      .then((result) => this.setState({ items: "test"} )
    );
  }

  componentDidMount() {
    this.fetchImages();
  }

  render() {
    console.log( this.state );
    return <div>Test</div>;
  }
}

As in the current situation, you don't need to bind your function. But remember, if you use this fetchImages in a callback (like in a button) you will need to bind it. If you use an arrow function it is bond automatically.

class ItemsPage extends React.Component {
  state = { items: null };

  fetchImages = () =>
      axios.get( "https://api.instagram.com/v1/users/self/media/recent/?access_token=" )
      .then((result) => this.setState({ items: "test"} )
    );

  componentDidMount() {
    this.fetchImages();
  }

  render() {
    console.log( this.state );
    return <div>Test</div>;
  }
}

Upvotes: 5

Related Questions