0

So, I'm simply trying to set state in my react app. Simply get data from Axios, and then set state. But no matter what I do, the state will not set. I've tried putting it in a callback since it's async and putting it my component did mount and component did update alas nothing. any pointers?

class App extends Component {
  componentDidUpdate() {}

  constructor(props) {
    super(props);
    this.state = {
      Catogories: [
        "Business",
        "Entertainment",
        "General",
        "Health",
        "Science",
        "Sports",
        "Technology"
      ],
      CatPics: [],
      TopStories: [],
      Selection: [],
      Sources: [],
      selected: false
    };
  }
  GeneratePic = () => {
    this.state.Catogories.forEach(Catogory => {
      axios
        .get(
          "https://api.pexels.com/v1/search?query=" +
            Catogory +
            "&per_page=15&page=1",
          {
            Authorization:
              "563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
          }
        )
        .then(res => {
          var object = { Catogory: res.photos[0].src.large2x };
          this.state.CatPics.push(object);
        });
    });
  };
  dump = x => {
    this.setState({ TopStories: x }, console.log(this.state.TopStories));
  };
  TopStories = () => {
    console.log("working");
    axios
      .get(
        "https://newsapi.org/v2/top-headlines?country=us&apiKey=91bec895cf8d45eaa46124fb19f6ad81"
      )
      .then(res => {
        console.log(res);
        const data = res.data.articles;
        console.log(data);
        this.dump(data);
      });
  };
  • 1
    `this.state.CatPics.push` mutates the state. Use `this.setState` function instead and always avoid mutating the current (or older) state object. – Emile Bergeron Jan 16 '20 at 18:24
  • Does this answer your question? [Why can't I directly modify a component's state, really?](https://stackoverflow.com/questions/37755997/why-cant-i-directly-modify-a-components-state-really) – Emile Bergeron Jan 16 '20 at 18:25
  • Another possible duplicate: [How to set state of response from axios in react](https://stackoverflow.com/q/41194866/1218980) – Emile Bergeron Jan 16 '20 at 18:26
  • [Correct modification of state arrays in ReactJS](https://stackoverflow.com/q/26253351/1218980) – Emile Bergeron Jan 16 '20 at 18:26
  • Also, [`setState` second argument should be a function](https://stackoverflow.com/q/42038590/1218980) but you've just put a `console.log` directly, which won't do what you think it does. – Emile Bergeron Jan 16 '20 at 18:28
  • Thanks for all of the help, I went ahead and looked up async/await for mutating the state. I'm currently trying apply this logic to the topstories() function. any pointers there ? :) – mekhi brodie Jan 25 '20 at 03:38

2 Answers2

2

You are doing two things wrong.

  1. Don't mutate the state
  2. Don't do async actions inside loop and then use same loop variable inside async callback because at that point in time, loop variable will have some other value and not the respective iteration category.
  GeneratePic = async () => {
    const promises = this.state.Catogories.map(Catogory => {
      return axios
        .get(
          "https://api.pexels.com/v1/search?query=" +
            Catogory +
            "&per_page=15&page=1",
          {
            Authorization:
              "563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
          }
        )
        .then(res => {
          return res.photos[0].src.large2x;
        });
    });

    let photos = await Promise.all(promises);
    photos = this.state.Catogories.map((cat, index) => ({ [cat]: photos[index] }));
    this.setState({ CatPics: photos });
  };

getPics = cat => {
      return axios
            .get(
              "https://api.pexels.com/v1/search?query=" +
                cat +
                "&per_page=15&page=1",
              {
                Authorization:
                  "563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
              }
            )
            .then(res => {
              return { [cat]: res.photos[0].src.large2x };
            });

}

GeneratePic = async () => {
        const promises = this.state.Catogories.map(Catogory => {
          this.getPics(Catogory);
        });
        
        let photos = await Promise.all(promises);
        this.setState({ CatPics: photos });
      };
Zohaib Ijaz
  • 21,926
  • 7
  • 38
  • 60
-1

This should work.

Dont Mutate the state.

 GeneratePic = () => {
        this.state.Catogories.forEach(async Catogory => {
            await axios
                .get(
                    "https://api.pexels.com/v1/search?query=" +
                    Catogory +
                    "&per_page=15&page=1", {
                        Authorization: "563492ad6f91700001000001d33b5d31a9a145b78ee67e35c8e6c321"
                    }
                )
                .then(res => {
                    var object = { Catogory: res.data.photos[0].src.large2x };
                    const cPics = [...this.state.CatPics];
                    cPics.push(object);
                    this.setState({
                        CatPics: cPics
                    })
                });
        });
    };
  • 2
    It's not me who downvoted you, but I think you should add an explanation what your codes does. Code-only answers are usually disliked here at Stack Overflow. – nalply Jan 16 '20 at 19:08
  • Thanks so much, this code actually worked and while I do have a good grasp of async/await I'm not sure why this works I've been trying to apply this concept to my other function (TopStories()) but I'm not how to implement because I'm not a 100% on how this works. But it does, and thanks for that, so it gets an upvote from me :) – mekhi brodie Jan 24 '20 at 13:11