I am fetching to get data from the server before the app is rendered, by store that data
into the redux store.
And facing this error:
Error: could not find react-redux context value; please ensure the component is wrapped in a
in _app.tsx
:
function MyApp({ Component, pageProps, data }: AppProps & { data: any }) {
console.log(data); // data is here
const dispatch = useDispatch();
useEffect(() => {
// Dispatch an action to store the fetched data in Redux store
dispatch(saveData(data));
}, [dispatch]);
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
const data = await fetch(`http://base-url/my-route`).then((res) => res.json());
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps, data };
};
export default MyApp;
store is exported from store.ts, and I am able to use those useDispatch and useSelector well in other parts of the app.
2
Answers
You can not use
useDispatch
outside theProvider
.You can use
useDispatch
inside yourComponent
, but not inMyApp
,because
Component
is inside theProvider
with the connectedstore
, butMyApp
is not:There are 3 solutions:
store
objectstore
object directly (withoutuseDispatch
)Loader
component, which can useuseDispatch
1. Add the data during the creation of the initial
store
objectYou surely have code to create the store somewhere, e.g.:
You might be able to create the initial state
myInitialState
with your data fromgetInitialProps
already included:I think this would be the cleanest solution, because it is exactly inline with both the React and the Redux concepts.
(Apparently
createStore
is deprecated and there is a new, much more complicatedsyntax with
configureStore
andcreateSlice
, which I’m not yer familiar with.)2. Use the
store
object directlyYou can not use
useDispatch
insideMyApp
, but you do have thestore
object available there.The
store
object has adispatch
and agetState
method, which you can use, e.g.:I think this is ok, but more like a "workaround" than a "solution", because using the
store
methods directlyseems a bit more low level than using the
Provider
, and probably intended for more advanceduse cases.
3. Create a ‘Loader’ component
You can create a component inside the
Provider
, and put yourdispatch
logic there.Alternatively you could create a Wrapper HOC
around the
Component
, if more appropriate.This seems pretty hacky to me, because is (mis-)uses a component as a kind of "life cycle hook",
and there is no logical relation between the
DataLoader
and the location where it is put insidethe code (it could really be anywhere, as long as the component is rendered at the right time).
for me its getting for useSelector how to resolve