How to render all component after an async call?

Viewed 114

I'm new to React and I'm currently setup my first project using Gatsby. Essentially I'm creating a website that use an API created with Strapi. So far, I would like to load the navbar items using an API call like that: http://localhost:3001/sections, where for sections, I mean the items of the navbar.

For doing so, I have defined an Index page like that:

import React from "react"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"

import "../styles/css/begreentannery.css"

const IndexPage = () => {
  return (
    <BGTState>
      <Layout>
        <SEO title="Home" />
      </Layout>
    </BGTState>
  )
}

export default IndexPage

the BGTState contains the getSections() method that is used inside Layout:

import React, { useContext, useEffect } from "react"
import PropTypes from "prop-types"
import { injectIntl } from "gatsby-plugin-intl"
import BGTContext from "../../context/bgt/bgtContext"
import { Spinner } from "react-bootstrap"
import Footer from "./footer"
import SearchState from "../../context/search/SearchState"
import Search from "../../components/search"
import NavbarMobile from "../../components/layout/navbarMobile"
import NavbarDesktop from "../../components/layout/navbarDesktop"

const Layout = ({ children, intl }) => {
  const bgtContext = useContext(BGTContext)
  const { loading, getSections, sections } = bgtContext

  useEffect(() => {
    getSections()
    //eslint-disable-next-line
  }, [])

  return !loading ? (
    <>
      <NavbarMobile sections={sections} />
      <NavbarDesktop sections={sections} />
      <SearchState>
        <Search />
        <div className="container-fluid">
          <div className="main">
            {children}
            <Footer />
          </div>
        </div>
      </SearchState>
    </>
  ) : (
    <div className="container" style={{ height: "100vh" }}>
      <div className="row h-100 justify-content-center align-items-center">
        <Spinner animation="grow" />
      </div>
    </div>
  )
}

Layout.propTypes = {
  children: PropTypes.node.isRequired,
}

export default injectIntl(Layout)

the problem is in the code above, essentially I call useEffect hook which grab the sections from the API. So, until the sections are downloaded, I stop the code like so:

 return !loading ? (

this is the getSections() method inside BGTState:

const getSections = async () => {
    try {
        setLoading()

        const res = await axios.get(
        `${process.env.API_URL}/sections?_sort=order:ASC`
        )

        dispatch({
        type: GET_SECTIONS,
        payload: res.data,
        })
    } catch (err) {
        dispatch({
        type: GET_SECTIONS,
        payload: err.response.msg,
        })
    }
}

in the Index page all works fine, but the problem is in the CollectionsPage, infact I have this structure:

import React from "react"
import { injectIntl } from "gatsby-plugin-intl"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import CollectionState from "../context/collection/collectionState"
import Collection from "../components/collection"

const CollectionsPage = ({ intl }) => {
  return (
    <BGTState>
      <Layout>
        <SEO
          lang={intl.locale}
          title={`${intl.formatMessage({ id: "collections" })}`}
        />

        <CollectionState>
          <Collection id={1} />
        </CollectionState>
      </Layout>
    </BGTState>
  )
}
export default injectIntl(CollectionsPage)

essentially, the component <CollectionState> isn't mounting 'cause in Layout there is the async call on getSections().

So in Collection component, I have:

import React, { useContext, useEffect } from "react"
import CollectionContext from "../context/collection/collectionContext"
import { Link } from "gatsby"

const Collection = ({ id }) => {
  const collectionContext = useContext(CollectionContext)
  const { loading, collection, getCollection } = collectionContext

  useEffect(() => {
    getCollection(id)
  }, [])

  if (loading) return React.Fragment

  return (
    <div className="container">
      <div className="row">
        {/*
        <img
          src={`${process.env.API_URL}${collection.feature_media.url}`}
          className="w-100 mt-2 mb-2"
          alt={""}
        />*/}
        <Link to="#" className="bg-caption bg-no-underline">
          fall/winter 20/21
        </Link>
      </div>
    </div>
  )
}

export default Collection

which generate that error:

enter image description here

and of course getCollection is not called and will generate other errors in the Collection component

How can I revisit this mechanism? Essentially I have to:

  1. Load all the sections
  2. Load all the components
0 Answers
Related