Search code examples
javascriptreactjsdynamic-typing

Objects are not valid as a React child (found: [object Promise]) Error in data state attribute


I cannot understand, why do I keep getting "Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead." error.

export async function LobbyPage(props) {
let fetched;
const [data, setState] = useState(null);
axios.get("http://127.0.0.1:8000/api_shop/")
.then(res => {
    fetched = res.data;
    setState(fetched);
})
return ( 
    <>
    <CatNav />
    <main>
        {data.map((current) => (
            <div className="card">
                <img src={current.photo} alt="Nothing"/>
                <div className="card-body">
                    <h5 className="card-title">{current.name}</h5>
                    <p className="card-text">
                        {current.desc}
                    </p>
                    <a href="#" className="btn btn-primary"></a>
                </div>
            </div>
        ))}
    </main>
    </>
)}

It must fetch json data from my DRF backend and just render it via data.map state attribute. Can somebody help with it?

EDIT: Data is being fetched as well, just something wrong with state and map()


Solution

  • This component isn't necessarily producing the error. But the component that uses it is. That's because this component doesn't return JSX, it returns a Promise:

    export async function LobbyPage(props) {
    

    async functions always return a Promise. The component shouldn't be async:

    export function LobbyPage(props) {
    

    Aside from that... Don't make AJAX calls directly in the component's rendering. That will invoke the AJAX operation every time it renders. And if the operation updates state, that will trigger a re-render and an infinite render loop.

    You can use useEffect with an empty dependency array to invoke the AJAX operation once when the component first loads:

    const [data, setState] = useState(null);
    
    useEffect(() => {
      axios.get("http://127.0.0.1:8000/api_shop/")
      .then(res => {
        setState(fetched);
      });
    }, []);
    

    You also don't need the fetched variable, it's not doing anything meaningful.

    Additionally, if you're mapping over data in the rendering then don't initialize it to null, since you can't call .map() on null. Initialize it to an empty array:

    const [data, setState] = useState([]);