I used a structure using React Hooks. It is based on a global Context that contains a combination of reducers (as in the Redux). Also, I widely use custom hooks to separate logic. I have a hook that contains asynchronous API requests and it has become quite cumbersome and I have the opportunity to split almost every function of this hook into other hooks, but each of these functions uses a global context (more precisely - dispatch from useReducer()).
providers/Store.js
import React, { createContext, useReducer } from 'react';
export const StoreContext = createContext();
export const StoreProvider = ({ children }) => {
/**
* Store that contains combined reducers.
*/
const store = useReducer(rootReducer, initialState);
return (
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
};
hooks/useStore.js
import { useContext } from 'react';
import { StoreContext } from '../providers';
export const useStore = () => useContext(StoreContext);
hooks/useFoo.js
import { useCallback } from 'react';
import { useStore } from './useStore';
export const useFoo = () => {
const [, dispatch] = useStore();
const doFoo = useCallback(
async params => {
dispatch(actions.request());
try {
const res = await SomeService.getSomething(params);
dispatch(actions.add(res));
dispatch(actions.success());
} catch (error) {
dispatch(actions.failure());
}
},
[dispatch]
);
return { doFoo };
};
hooks/useBar.js
import { useCallback } from 'react';
import { useStore } from './useStore';
export const useBar = () => {
const [, dispatch] = useStore();
const doBar = useCallback(
async params => {
dispatch(actions.request());
try {
const res = await SomeService.getSomething(params);
dispatch(actions.success());
dispatch(actions.add(res));
} catch (error) {
dispatch(actions.failure());
}
},
[dispatch]
);
return { doBar };
};
hooks/useNext.js
...
import { useStore } from './useStore';
export const useNext = () => {
const [, dispatch] = useStore();
...
};
components/SomeComponent.js
const SomeComponent = () => {
// use context
const [store, dispatch] = useStore();
// and here is the context
const { doFoo } = useFoo();
// and here
const { doBar } = useBar();
// and here
useNext();
return (
<>
<Button onClick={doFoo}>Foo</Button>
<Button onClick={doBar}>Bar</Button>
// the flag is also available in another component
{store.isLoading && <Spin />}
</>
)
}
Internally, hooks can reference a state queue owned by component. (Under the hood of React’s hooks system - Eytan Manor )
useContext
is just to reference a global state from the relative Context Provider. There is almost no overhead from useContext
as you are concerned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With