Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can't update the array defined with useState in useEffect hook in React-Native

I have a feedItems array. I want to set this array’s items according to axios get request’s response. In the screen, I want to show the information of the elements of this array. So, before everything, I must set this array so that I will be able to show the info of elements of this array.

I have no problem while making an API request and I am sure that the response.data is not empty. However, when I use the setFeedItems(...feedItems, response.data[i]); function, I get the following error.

[Unhandled promise rejection: TypeError: Invalid attempt to spread non-iterable instance.]

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here is the code:

const [feedItems, setFeedItems] = useState([{}]);

  useEffect(async () => {
    console.log("here");
    let accessToken = await AsyncStorage.getItem("accessToken");
    const response = await axios
      .get(
        "http://repor****-env-1.eba-nj*******/feed",
        {
          headers: {
            Authorization: "Bearer " + accessToken,
          },
        }
      )
      .then((response) => {
        for (let i = 0; i < response.data.length; i++) {
          setFeedItems(...feedItems, response.data[i]);
        }

        //console.log(feedArray);
        console.log(feedItems);
      });
  }, []);

>Solution :

The problem is that you’re spreading out [{}] into discrete arguments to setFeedItems. To append response.data to feeditems, you do this:

.then((response) => {
    setFeedItems(feedItems => [...feedItems, ...response.data]);
    // No `console.log(feedItems)` here, it will show you outdated information
});

Notice:

  • Using the callback form, since you’re updating state based on existing state, so you want to be sure to be using the up-to-date state.
  • The [] around the return value so you’re creating an array and spreading the items out into it.
  • That it’s spreading both the old feedItems and the new response.data out into that new array.

Also, in the normal case, your feedItems would start out with an empty array, not an array with an empty object in it. So:

const [feedItems, setFeedItems] = useState([]);

Separately: useEffect won’t do anything useful with the promise an async function returns (and does look at the return value, to see if it’s a function), so you shouldn’t pass an async function into it. Since you’re already using explicit promise callbacks, there’s no reason for the await and the async function. Also, you should handle promise rejection.

Putting all of that together:

const [feedItems, setFeedItems] = useState([{}]);

useEffect(() => {
    AsyncStorage.getItem("accessToken").
    then(accessToken => axios.get(
        "http://repor****-env-1.eba-nj*******/feed",
        {
            headers: {
            Authorization: "Bearer " + accessToken,
        },
    }))
    .then((response) => {
        setFeedItems(feedItems => [...feedItems, ...response.data]);
    })
    .catch(error => {
        // ...handle/report the fact an error occurred...
    });
}, []);

Live Example:

const { useState, useEffect } = React;

// Mock `AsyncStorage`
const AsyncStorage = {
    getItem() {
        return Promise.resolve("some token");
    },
};

// Mock `axios`
const axios = {
    get() {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve({data: [
                    {id: 1, text: "Item 1"},
                    {id: 2, text: "Item 2"},
                    {id: 3, text: "Item 3"},
                    {id: 4, text: "Item 4"},
                ]});
            }, 400);
        });
    },
};

const Example = () => {
    const [feedItems, setFeedItems] = useState([]);

    useEffect(() => {
        AsyncStorage.getItem("accessToken").
        then(accessToken => axios.get(
            "http://repor****-env-1.eba-nj*******/feed",
            {
                headers: {
                Authorization: "Bearer " + accessToken,
            },
        }))
        .then((response) => {
            setFeedItems(feedItems => [...feedItems, ...response.data]);
        })
        .catch(error => {
            // ...handle/report the fact an error occurred...
        });
    }, []);

    return <div>
        {feedItems.map(({id, text}) => <div key={id}>{text}</div>)}
    </div>;
};

ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading