Is there any benefit of using React Query when response is not being returned from the component? - reactjs

I am wondering if there is any benefit of using React Query instead of the traditional following approach in cases where the response does not target the output of the component.
useEffect( () => {
const callback = async () => {
const env = await axios.get(`/api/environment`).then(res=>res.data);
window.localUrl = env.url;
};
callback();
}, []);
The above code assigns an API response to a global variable. Would it be beneficial to use React Query in that case and why?
P.S. Please do not make any comments about the usage of global variables. Take is as an example.

There's no significant benefit to using React Query instead of the traditional approach for this particular case, as the response does not directly target the output of the component. However, if you plan on using the API response in multiple places or if you need to handle API errors and loading states, React Query can provide a convenient and centralized way to manage API requests in your React components. Additionally, React Query has features for caching and optimizing API requests, which can improve the performance and UX of your application.

Related

Next.js: How to cache initial data on the server (same for all users)

I'm learning Next.js and started building one of my first applications - https://www.codart.io/
If you visit the site, you'll notice a delay until the collections become available: The application makes an initial graphql request to retrieve a json file with a number of NFT collections, which takes a few seconds. This data needs to be available across different components, so I built a global context to store the data (I'm not sure this is the best approach):
https://github.com/bartomolina/codart/blob/main/app/components/collections-context.tsx
const ArtBlocksContext = createContext({
aBCollections: [] as IABCollection[],
cACollections: [] as ICACollection[],
fetchCACollections: () => {},
});
export const useArtBlocks = () => useContext(ArtBlocksContext);
export const ArtblocksProvider = ({ children }: React.PropsWithChildren) => {
...
useEffect(() => {
fetchCACollections();
execute(ArtblocksCollectionsDocument, {}).then((result) => {
I wonder what would be the best way to cache this data (as the data doesn't change often, it could be cached at build time, or ideally, indicating an expiration date i.e. 24 hours). Note that the cache will be shared between all users.
I've been looking at some similar posts, and I got some ideas, although it seems there isn't a clear and simple way to do this:
Using Redux - Seems an overkill for a small project like this.
Use some custom caching libraries - I'd rather not use any external libraries.
Use getStaticProps along with the Context API - It seems you can't getStaticProps within the _app.ts page, so you would need to call it in every page where the context is used?
Use SWR and an API call - SWR will cache the data, but on a per-user basis? i.e. the first time a user visits the site, it will still take a few seconds to load.

Zustand fetch with API call useEffect best practice

When fetching state from an API with Zustand in a useEffect function what is the best practice for doing that? Right now I am using it very simply:
export interface ModeState{
modes: Mode[];
fetchModes: () => void;
}
export const useModeStore = create<ModeState>((set) => ({
modes: [],
fetchModes: async () => {
const modes: AcquisitionMode[] = await API.get(`/acquisition-modes`);
await set({ modes });
},
}));
In component render function:
const modeStore = useModeStore()
const modes = modeStore.modes
useEffect(() => {
modeStore.fetchModes()
}, [])
However the documentation seems to imply there are multiple ways this could be written to be more efficient in terms of performance, especially if my store grows more complex with more values and fetch functions. Is it best practice to make one store per API call? Use slices to get just the part of the store you need in each component? Should I be using the store differently in useEffect? I can't find a clear example online of how you should use the store in useEffect. The subscribe documentation does not seem to apply to the use case where you are using the store to fetch values with an async function.
I have used zustand in a similar fashion in the past. I would often have a sync method on the store which I call in a useEffect and pass to it any state that is available to the component and not the store. Another possibility could be to let a library optimized for fetching get the data and make it available to the store once fetched.
What the documentation refers to with regard to performance is that you can indeed select parts of your store with a provided selector. In these cases a rerender will only happen when
the previous and current selected value are different or
a custom provided equality function states that previous and current values are different.
If you want to get into more detail with regard to performance I can recommend this this article here (disclaimer, I wrote it)
Even so, those performance considerations do not influence so much how you would trigger a fetch from, say, a useEffect hook.

How to share data across multiple components with react-query useMutation

I'm looking for a solution to share data across a React-Query mutation without having to create my own internal state or context.
I created a custom hook that takes care of the API call.
myData.ts
const useDataMutation = () => useMutation('MY_DATA_MUTATION', postData);
Then, I use my custom hook in different components.
Component1 is in charge of mutating. The response data will be available in data once the mutate is successful.
Component1.tsx
const { mutate, data } = useDataMutation();
useEffect(() => mutate('some_data'), []);
In another nested component, I want to access the data which came back from the response. But I don't want to pass down the data to 3-4 layers of components. And I wanted to avoid using a Context to access this data.
What I want is something like this:
Component2.tsx
const { data } = useDataMutation();
console.log({ data }); // log data once available.
But in this example, the data from Component2.ts is always undefined.
Is there a simple way to achieve something like this?
Thank you.
at the moment, mutations don't share data across instances like queries do. There is an open issue about it, and contributions are welcome.
If you're using #apollo/client then you can read the previously fetched data directly from the cache.
import Query from './query.ts'
const { todo } = client.readQuery({
query: Query,
variables: {}
})
That will not fetch the data from your server again and instead fetch it from the apollo cache. So you can fetch it using the hook or in the parent component and then 5 levels down you can just pull it again from the cache using the same hook.
When you're using a mutation it will update data in the cache if the properties in the query is the same as before, so if you have a query for getUser and a mutation for updateUser I think the mutation should automatically update the getuser cache data if the data aligns with the mutation data. I'm not sure about this.

How to perform a server side data fetching with React Hooks

We just start moving into React Hooks from the React life-cycle and one of the things that we noticed, is that there's no straightforward way to run something similar to ComponentWillMount for loading data before sending the rendered page to the user (since useEffect is not running on SSR).
Is there any easy way supported by React to do so?
I had the same problem. I've managed to solve it with a custom hook and by rendering application twice on the server-side. The whole process looks like this:
during the first render, collect all effects to the global context,
after first render wait for all effects to resolve,
render the application for the second time with all data.
I wrote an article with examples describing this approach.
This is a direct link to the example form article on CodeSandbox.
Also, I have published an NPM package that simplifies this process - useSSE on GitHub.
This is a little tricky but one way around is to do the fetch directly in the component as in
function LifeCycle(props){
console.log("perform the fetch here as in componentwillmount")
const [number, setNumber] = useState(0)
useEffect(() => {
console.log("componentDidMount");
return () => {
console.log("componentDidUnmount");
};
}, []);
}

apollo-client used to make multiple requests to make a real-time search

We're developing a search engine inside an app with Apollo and we do not know exactly how to develop a real-time search engine that makes a request to the server on every keyboard press.
On the documentation it says that we must use the new <Query /> component, but I see that this case mostly fits with firing a manual query: https://www.apollographql.com/docs/react/essentials/queries.html#manual-query
I don't know if I'm correct, or maybe we should use it in another way.
thanks!
As it is said at a link you shared, if you wanted to delay firing your query until the user performs an action (your case), such as clicking on a button, you want to use an ApolloConsumer component and directly call client.query() instead.
Query component can't be used in this situation because when React mounts a Query component, Apollo Client automatically fires off your query during rendering.
UPDATE
With Apollo Client V2.6, it is now possible to make a Query to the server manually using a hook. The hook that you want is useLazyQuery.
You'd have something like this;
const [onSearch, { called, loading, data }] = useLazyQuery(
SEARCH_QUERY,
{ variables: { searchText: state.searchText } }
);
Then you can call the onSearch function whenever your text changes inside a useEffect like below.
useEffect(() => {
onSearch()
}, [state.searchText])
Note that you might want to dounce your onSearch function such that you don't hammer your server on every key stroke.

Resources