React - trying to save fetched data in a variable but the variable returns empty

Viewed 65

I fetched json data with async await and i wanted to save the fetched data in a variable in order to be able to use it with a map in my component, the data comes in properly inside the function - i checked with an alert , and also in the variable inside the function it does display all the data , but somehow the variable outside the function returns empty . here is some code: both alerts in the following code return the right data.

export let fetchPosts = [];
export async function FetchPosts() {
    await axios.get('https://jsonplaceholder.typicode.com/posts').then(
        res => {
            alert(JSON.stringify(res.data))
            fetchPosts = JSON.stringify(res.data);
            alert(fetchPosts)
        }
    ).catch(err => {
        alert('err');
    })
}

import { fetchPosts } from '../services/post';
import { FetchPosts } from '../services/post';

export default function Posts() {
    function clickme() {
        FetchPosts()
    }
    return (<>
        <button onClick={clickme}>Click me</button>
        {fetchPosts.map((post, index) => (
            <div key={post.id} className="card" style={{ 'width': '16rem', 'display': 'inline-block', 'margin': '5px' }}>
                <div className="card-body">
                    <h6 className="title">{post.title}</h6>
                    <p className="card-text">{post.body}</p>
                </div>
            </div>
        ))}
    </>)
}
1 Answers

State is the issue

React doesn't automatically reload on your singleton fetchPosts. Instead, try...

export function FetchPosts() {
    return axios.get('https://jsonplaceholder.typicode.com/posts');
}

then

import { useState } from 'react';
import { FetchPosts } from '../services/post';

export default function Posts() {
    const [posts, setPosts] = useState([]);
    function clickme() {
        FetchPosts().then(res => {
          setPosts(res.data);
        });
    }
    return (<>
        <button onClick={clickme}>Click me</button>
        {posts.map((post, index) => (
            <div key={post.id} className="card" style={{ width: '16rem', display: 'inline-block', margin: '5px' }}>
                <div className="card-body">
                    <h6 className="title">{post.title}</h6>
                    <p className="card-text">{post.body}</p>
                </div>
            </div>
        ))}
    </>)
}

https://codesandbox.io/s/jolly-almeida-q4331?fontsize=14&hidenavigation=1&theme=dark

If you want global state, that's another topic you should dive into entirely but you can do it with a singleton, you just need to incorporate it with hooks and an event emitter. I have a bit of a hacked version of this here https://codesandbox.io/s/react-typescript-playground-forked-h8rpu but you should probably stick to redux or mobx or AppContext which is more of a popular pattern.

Related