0

I'm using a get request to get info about a post from the backend, I receive the data fine, it's just an object with some of the values being arrays. For example the imageRoutes property has an array value. I've saved the response object into my state, but when I try to access the array information using dot or bracket notation or try to use array methods like '.length', it just comes up as undefined? Why is this?

    const [post, setPost] = useState({})
    const [error, setError] = useState('')

    useEffect(() => {
        fetchData()
    }, [])

    console.log(post)
    console.log(post.imageRoutes)
    console.log(post.imageRoutes.length)
    console.log(post.imageRoutes[0])
    
    const fetchData = async () => {
        await axios.post('/forums-post', {post_id: match.params.id})
            .then(res => {
                res.data.error ? setError(res.data.error) : setPost(res.data)
            })
    }
willmahon
  • 319
  • 4
  • 13
  • You're already in an `async` method, you don't need `.then`, just use `await` on the response again. – Dai Oct 27 '20 at 21:12
  • Does this answer your question? [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Heretic Monkey Oct 27 '20 at 21:29

1 Answers1

0

You're blending two different styles of asynchronous code: the traditional promise style (.then) and the more modern async/await style.

As a result, when you do:

const fetchData = async () => {
    await axios.post('/forums-post', {post_id: match.params.id})
        .then(res => {
            res.data.error ? setError(res.data.error) : setPost(res.data)
        })

What you're really doing, if we translate it to 100% async/await style, is ...

const fetchData = async () => {
    const res = await axios.post('/forums-post', {post_id: match.params.id})
    res.data.error ? setError(res.data.error) : setPost(res.data)
});

But you know what I don't see in that function? return! You're not returning anything, which explains why:

but when I try to access the array information using dot or bracket notation or try to use array methods like '.length', it just comes up as undefined?

If you simply add a return keyword (and keep the code all in a single style) ...

const fetchData = async () => {
    const res = await axios.post('/forums-post', {post_id: match.params.id});
    return res.data.error ? setError(res.data.error) : setPost(res.data);
});

... everything should work, and you should actually return a (not undefined) value ... or at least, you will if setPost/setError actually return something. If they don't, you might instead want to do:

const fetchData = async () => {
    const res = await axios.post('/forums-post', {post_id: match.params.id});
    res.data.error ? setError(res.data.error) : setPost(res.data);
    return res.data;
});
machineghost
  • 33,529
  • 30
  • 159
  • 234
  • 1
    The problem is that the OP thinks that `fetchData()` (and the `setPost` call within) will occur before `console.log(post);` but in React, the hooks for setting state are async, along with `fetchData`. There's no need to return anything from `fetchData`, since it would not be used (look at the call in `useEffect`). – Heretic Monkey Oct 27 '20 at 21:34
  • Thanks, should I just keep track of the loading state then, so the code is only run when the data is loaded? – willmahon Oct 27 '20 at 21:39
  • Thanks @HereticMonkey for that clarification; I didn't realize the async nature of `setState` was involved here. @willmahon yes, and in general that's how you want to do **everything** in React. Instead of worrying about *when* each component gets its data, you should just worry about *what* data each component has at any given moment (and if they don't have the necessary data, yet, they should `return null`). – machineghost Oct 27 '20 at 21:57