How to get running Gatsby page query data with React Context API?

Viewed 610

I'm working on a site where I have a gallery and custom build lightbox. Currently, I'm querying my data with a page query, however, I also use them in other components to display the right images and changing states. It is easier for me to store states in Context API as my data flow both-ways (I need global state) and to avoid props drilling as well.

I've setup my context.provider in gatsby-ssr.js and gatsby-browser.js like this:

const React = require("react");
const { PhotosContextProvider } = require("./src/contexts/photosContext");

exports.wrapRootElement = ({ element }) => {
    return <PhotosContextProvider>{element}</PhotosContextProvider>;

};

I've followed official gatsby documentation for wrapping my root component into context provider.

Gallery.js here I fetch my data and set them into global state:

import { usePhotosContext } from "../contexts/photosContext";

const Test = ({ data }) => {
    const { contextData, setContextData } = usePhotosContext();


useEffect(() => {
    setContextData(data);
}, [data]);


return (
    <div>
        <h1>hey from test site</h1>
            {contextData.allStrapiCategory.allCategories.map((item) => (
            <p>{item.name}</p>
        ))}
     <OtherNestedComponents />  
    </div>
);
};

export const getData = graphql`
    query TestQuery {
        allStrapiCategory(sort: { fields: name }) {
            allCategories: nodes {
                name
            }
        }
    }
`;

export default Test;

NOTE: This is just a test query for simplicity

I've double-checked if I get the data and for typos, and everything works, but the problem occurs when I try to render them out. I get type error undefined. I think it's because it takes a moment to setState so on my first render the contextData array is empty, and after the state is set then the component could render.

Do you have any idea how to work around this or am I missing something? Should I use a different type of query? I'm querying all photos so I don't need to set any variables.

EDIT: I've found a solution for this kinda, basically I check if the data exits and I render my component conditionally.

return testData.length === 0 ? (
    <div className="hidden">
        <h2>Hey from test</h2>
        <p>Nothing to render</p>
    </div>
) : (
    <div>
        <h2>Hey from test</h2>
        {testData.allStrapiCategory.allCategories.map((item) => (
            <p>{item.name}</p>
        ))}
    </div>
);

However, I find this hacky, and kinda repetitive as I'd have to use this in every component that I use that data at. So I'm still looking for other solutions.

1 Answers

Passing this [page queried] data to root provider doesn't make a sense [neither in gatsby nor in apollo] - data duplication, not required in all pages/etc.

... this data is fetched at build time then no need to check length/loading/etc

... you can render provider in page component to pass data to child components using context (without props drilling).

Related