1

My array isn't getting new entries added to it via the setState getter.

Code:

let calledOut = false;
export default function PayStation () {
    const [records, setRecords] = useState([]);

    // problem snippet
    if (records.length === 0 && !calledOut) {
        calledOut = true;
        fetch('http://localhost:5000/api').then(
            response => response.json()
        ).then(
            data => {
                const payloadRecords = data["records"];
                // returning
                //     [{
                //         "attributes": {
                //             "type": "Contact",
                //             "url": "/services/data/v42.0/sobjects/Contact/0030U00001UPWYKQA5"
                //         },
                //         "Id": "0030U00001UPWYKQA5",
                //         "Name": "Contact25 Sequence Contact Manual Email"
                //     },
                //     {
                //         "attributes": {
                //             "type": "Contact",
                //             "url": "/services/data/v42.0/sobjects/Contact/0030U00001UPWYLQA5"
                //         },
                //         "Id": "0030U00001UPWYLQA5",
                //         "Name": "Contact26 Sequence Contact Manual Email"
                //     }
                // ]
                setRecords((records => [...records, ...payloadRecords]));
                console.log("records size: " + records.length); // why is this still 0?
            }
        );
    }
    // end problem snippet

    return (records.length === 0 ? "loading..." :
        <div style={{
            height: '100vh',
            display: 'flex',
            maxWidth: 600,
            justifyContent: 'space-between',
            alignItems: 'center'
        }} >
            {records}
        </div>
    );
}

I think the requirement for state to change is that you clone the state variable (which I believe I'm doing), as opposed to assigning a reference to it and mutating the reference.

So, why isn't my array getting new entries?

7
  • 1
    Try setRecords([...records, ...payloadRecords]); Instead of setRecords((records => [...records, ...payloadRecords])); Commented May 8, 2022 at 21:36
  • thank for the suggestion, but still got an array size of 0 Commented May 8, 2022 at 21:38
  • @MarkoTaht That shouldn't make a difference, in this case prevState gets the same data Commented May 8, 2022 at 21:39
  • @NicholasZozaya Are you actually receiving data from backend? Have you made a console log? Commented May 8, 2022 at 21:39
  • 100% sure i'm getting 2 records from backend, revised the desc to show the payload Commented May 8, 2022 at 21:41

2 Answers 2

2

The body of the component should be a pure function. Side effects (such as data fetching) should be wrapped in useEffect. The following code should work:

export default function PayStation () {
  const [records, setRecords] = useState([]);

  useEffect(() => {
    const getRecords = () => {
      fetch('http://localhost:5000/api').then(
        response => response.json()
      ).then(
        data => {
          const payloadRecords = data["records"];
          setRecords((records => [...records, ...payloadRecords]));
        }
      );
    }
    
    getRecords()
  }, [])
  
  if (records.length === 0) return "loading..."

  return (
    <div style={{
      height: '100vh',
      display: 'flex',
      maxWidth: 600,
      justifyContent: 'space-between',
      alignItems: 'center'
    }} >
      {records.map((record) => <Record key={record.id} {...record} />)}
    </div>
  );
}

Sign up to request clarification or add additional context in comments.

2 Comments

sorry, I'm still getting 0 records in my array after adding console.log below setRecords(), I expected the array to have some records in it...
It won't show because the state updates happen asynchronously, and the log is run when that variable is still not filled. But it doesn't mean that you don't have a value there.
2

The issue seems to be that useState and setState are both being ran in the same call... And since they're both async the setState isn't setting a value to anything since the state hasn't been created yet. If you removed the calledOut variable it should work fine.

This is generally bad way to do fetching. I recommend doing

  useEffect(() => {
    // fetch stuff here
  }, []);

So this will be invoked after the states are made.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.