Iām finding myself reusing a hook to fetch the same data a lot, which looks like this:
import { useEffect, useState } from 'react';
import to from 'await-to-js';
import { useConnect } from 'frontity';
//
/**
*
* @param {number} id The ID of the post you want to fetch
* @param {number} category The ID of the category you want to fetch
* @returns A list of posts
*/
const useFetchPosts = (id, category) => {
const [post, setPost] = useState(null);
const { libraries } = useConnect();
useEffect(() => {
async function getPostById() {
const { api } = libraries.source;
let err;
let res;
let resData;
[err, res] = await to(
api.get({
endpoint: id ? `posts/${id}` : 'posts',
params: { _embed: true, categories: category },
})
);
if (!res) console.error(err);
[err, resData] = await to(res.json());
if (!resData) console.error(err);
setPost(resData);
}
getPostById();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return post;
};
export default useFetchPosts;
Then at component level I find myself using this a lot:
const allSamples = useFetchPosts(null, 12); // '12' is the id of a page containing data (samples) I need
Iām thinking at this point it makes more sense to add it to the global state, in my index file of my theme package (with roots etc) but Iām not sure how to do this.
Can anyone advise how to take the above hook and fetch the data I need in state rather than in each component? That way I can just access it directly from state
You would call this once you have the data returned from the get call, so I guess you could call it either in your useFetchPosts component, or in the component that receives the post returned by useFetchPosts.
and I added this to handlers in my components/index.js fileā¦ but if I console.log(state) from one of my pages Iām not seeing the data Iād expect to see.
If your handler pattern is @samples/:slug, it means it expects that as the āurlā for the content you want to fetch and get.
So
beforeSSR: async ({ actions }) => {
// this will preload the posts with category 'some-category'
// and put them in `state.source.data['@samples/some-category']`
await actions.source.fetch('@samples/some-category');
},
and in your component
const somePosts = state.source.get('@samples/some-category'); // <- The data will exist
Alternatively, if you donāt want to preload all posts at all times:
const SomePost = ({ actions, state }) => {
useEffect(() => {
// No need to use `async/await` here
actions.source.fetch('@samples/some-category);
}, []);
// The data will not exist at first, `dataPost.isReady` will be false.
// But then, it will rerender when `actions.source.fetch` is finished.
const somePosts = state.source.get('@samples/some-category');
// This will work just fine.
return somePosts.isReady ? <Post link="/some-post" /> : <Loading />;
};
const allSamples = state.source.get('@samples/samples');
if (allSamples.isFetching) return <Loading />;
I have access to all of the returned samples in allSamples.items this way. It works perfectly and the site speed has rocketed having to only fetch this data once.
Iām not sure whatās going to happen when I have a load of samples to grab, but thatās the next bridge to crossā¦