0

I am using React hooks and I need to store the data from my server which is an object, to a state.

This is my state:

  const [sendingTime,setSendingTime] = useState({})

This is how I set it inside useEffect:


    const getTime= () =>{
        axios.get("https://localhost:1999/api/getLastUpdatedTime")
            .then(res => {

                console.log(res.data)

                setSendingTime({sendingTime : res.data})
          
                console.log('sendingTime is coimng',sendingTime)

            })
            .catch(err => console.error(err))
    }


 useEffect(() => {
        getCount()
        getTime()
    },[])

Now when I console.log the object state it returns an empty object. Although if I set the object to any variable and then console.log it it doesn't return an empty object. But both ways I am unable to access the properties of the object.

Edit

This is what I was doing previously:

 const[time,setTime] = useState({
        totalComplaintsTime: '00:00',
        resolvedComplaintsTime: '00:00',
        unresolvedComplaintsTime:'00:00',
        assignedComplaintsTime:'00:00',
        supervisorsTime:'00:00',
        rejectedComplaintsTime:'00:00'

    })

  const getTime= () =>{
        axios.get("https://localhost:1999/api/getLastUpdatedTime")
            .then(res => {

                console.log(res.data)

                setTime({
                    totalComplaintsTime: res.data.Complaints[0].updatedAt,
                    resolvedComplaintsTime:  res.data.Resolved[0].updatedAt,
                    unresolvedComplaintsTime: res.data.Unresolved[0].updatedAt ,
                    assignedComplaintsTime: res.data.Assigned[0].updatedAt ,
                    rejectedComplaintsTime: res.data.Rejected[0].updatedAt,
                    supervisorsTime: res.data.Supervisors[0].updatedAt
                })

            

            })
            .catch(err => console.error(err))
    }

 useEffect(() => {

        getCount()

        // getTime()

        getTime()
    },[])

And this is how I used the states to set the dynamic values :

Last updated at {time.resolvedComplaintsTime}

This is working perfectly fine but I wanted to store the data in an object state and then access it, which would've been easier and more efficient. Also I wanted to pass this object to another component. That is why I wanted to make a state and store the data in that state.

Solved

So the main problem was accessing the data throughout the component. This is the solution:

sendingTime is being initialized but only when a render occurs. So we add a piece of code to check if that state is initialized or not.

This is where I wanted to display the data.

 <div key={sendingTime.length}  className={classes.stats}>
            <UpdateIcon fontSize={"small"} /> Last updated at{" "}
              {Object.keys(sendingTime).length > 0 &&
              sendingTime.Complaints[0].updatedAt}
          </div>

This way I can access the properties of the object stored in the sendingTime state very easily.

3
  • You prob don't want the length as a key for the item. Also, you don't need to wrap fontSize="small" in brackets. Commented Apr 21, 2020 at 14:18
  • what else can i give as the key? Commented Apr 22, 2020 at 12:18
  • Well, it's hard to say given the partial snipped, but you would probably want a unique key for the item like a database ID or unique name. Commented Apr 24, 2020 at 16:53

3 Answers 3

1

setSendingTime comes from a useState so it is asynchronous:

When you call:

setSendingTime({sendingTime : res.data})
console.log('sendingTime is coimng',sendingTime)

The state sendTime has not been updated, so it display the init value which is {}

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

Comments

1

The other answers are correct, setState is asynchronous so you will only be able to get sendingTime's new value on the next re-render. And as @Enchew mentions, you probably don't want to set an object as that value most likely.

Try this instead:

const [data, setData] = useState(undefined)

const getTime = () => {
  axios.get("https://localhost:1999/api/getLastUpdatedTime")
    .then(({ data }) => {
      console.log(data)
      setData(data)
    })
    .catch(err => console.error(err))
}

useEffect(() => {
  getCount()
  getTime()
}, [])

if (!data) return <p>No data...</p>

return (
  <>
    <p>Complaints: {data.Complaints[0].updatedAt}<p>
    <p>Resolved: {data.Resolved[0].updatedAt}<p>
    <p>{/* ...etc... */}</p>
  </>
)

You should see the value you're expecting to see in the console.log because you're using the locally scoped variable, not the asynchronous value, which will only be updated on the next re-render.

12 Comments

Ok yes, I do see the data now, but I am logging 'data' right now. If I am log sendingTime it still shows an empty object. Since it's empty I still can't access its properties throughout the component.
Because it is async and won't be set till next re-render (as I mentioned). This is a known property of setting state with a hook in React
How can I fix it then? I also tried to store the data in a variable object, that maybe it will work that way, I could see the variable in console.log but then again there was still the problem of accessing its properties. It gave me this error = TypeError: Cannot read property '0' of undefined
You need to provide more context/examples, because what you have doesn't show me what you're trying to do. You must access to sendingTime value in your component and it will match the value you set from setSendingTime on the next re-render (not the current one)
Okay so I have one useEffect in there I am calling a function getTime. In that function I fetch the data which is an object = {Complaints: Array(1), Resolved: Array(1), Assigned: Array(1), Rejected: Array(1), Unresolved: Array(1), …}. And I set the sendingTime with the res.data this way setSendingTime(res.data) . I want to use this state to display the data in the return function of the component this way = Last updated at {sendingTime.Complaints[0].updatedAt} . But it gives me this error = TypeError: Cannot read property '0' of undefined
|
0

setSendingTime works asynchronously and your object may have not been saved in the state yet. Also pay attention to the way you save the time in your state, you are wrapping the result of the data in another object with property sendingTime, which will result in the following object: sendingTime = { sendingTime: {/*data here */} }. If you are running for sendingTime: {/*data here */} try the following:

const getTime = () => {
  axios
    .get('https://localhost:1999/api/getLastUpdatedTime')
    .then((res) => {
      console.log(res.data);

      setSendingTime(res.data);

      console.log('sendingTime is coimng', sendingTime);
    })
    .catch((err) => console.error(err));
};

Also have a look at this - how to use hooks with a callback: https://www.robinwieruch.de/react-usestate-callback

6 Comments

ok I changed it to sendingTime(res.data) and I also added sendingTime to the useEffect deps like this : useEffect( () => { getCount() getTime() } , [sendingTime]). It does console.log the object now but it keeps on rerendering. It never stops.
What kind of data is returned from the axios call? If it is an object and this object is defined by a unique property (for example id), use that property in the array of the second argument.
Also, how many times do you want to call useEffect()? If you want to call it ONLY ONCE after the component is initially rendered, use an empty array. Currently, when you pass the object you are making an infinite loop. I'll explain - you call getTime and change the data of time. After that, you tell React, that your data has changed (this is done when passing the time parameter in the array) and it calls useEffect again. Since your data is an object, React is comparing its reference (which after every axios call is different).
This is being returned from res.data = {Complaints: Array(1), Resolved: Array(1), Assigned: Array(1), Rejected: Array(1), Unresolved: Array(1), …}. I want to call it once and I did had an empty array in the useEffect but due to that my state wasn't being intialized at all. It was empty
This is how I want to access its properties and display the data throughout the component : Last updated at {sendingTime.Complaints[0].updatedAt} . But sendtingTime isn't being initialized at all, also, it gives me this error = TypeError: Cannot read property '0' of undefined.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.