I’m building an expo-app and I manage state with react-redux
, so my <Provider>
in is in the top level _layout file.
My problem is I’m working with expo notification and I need to get the title, body, and some data received from the server through the notification and dispatch it to the store for later use, but when I try to dispatch I got an error that says:
could not find react-redux context value
I realize that this error occurs because I try to use dispatch before wrapping the whole app in redux <Provider>
but I don’t know how I can do this. Below is my code.
import React from "react";
import { Stack, SplashScreen } from "expo-router";
import { useEffect } from "react";
import { useFonts } from "expo-font";
import FontAwesome from "@expo/vector-icons/FontAwesome";
import { Provider } from "react-redux";
import { persistor, store } from "../src/redux/store/store";
import { PersistGate } from "redux-persist/integration/react";
import * as Notifications from "expo-notifications";
import { router } from "expo-router";
import { useDispatch } from "react-redux";
import { addMessage } from "../src/redux/slice/system-messages";
export {
// Catch any errors thrown by the Layout component.
ErrorBoundary,
} from "expo-router";
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: "(tabs)",
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
function saveNotificationResponse() {
const dispatcher = useDispatch();
const subscription = Notifications.addNotificationResponseReceivedListener(
(response) => {
console.log(response.notification.request.content.data);
dispatcher(addMessage(response.notification.request.content.data));
}
);
return () => {
subscription.remove();
};
}
export default function _layout() {
useEffect(() => {
saveNotificationResponse();
}, []);
const [loaded, error] = useFonts({
SpaceMono: require("../src/assets/fonts/SpaceMono-Regular.ttf"),
DMBold: require("../src/assets/fonts/DMSans-Bold.ttf"),
DMMedium: require("../src/assets/fonts/DMSans-Medium.ttf"),
DMRegular: require("../src/assets/fonts/DMSans-Regular.ttf"),
...FontAwesome.font,
});
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Stack>
<Stack.Screen
name="index"
options={{
title: "Home",
}}
/>
<Stack.Screen
name="[missing]"
options={{
title: "404",
}}
/>
<Stack.Screen
name="(tabs)"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="order/index"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="search/searchpage"
options={{
headerShown: false,
}}
/>
</Stack>
</PersistGate>
</Provider>
);
}
So when I try to run saveNotificationResponse()
I got this error how can I fix this and still save my response to the store? thanks
2
Answers
As you said your useEffect that triggers your useDispatch is outside your reducer wrapper.
You have to place your useEffect somewhere inside your
<PersistGate/>
.You could for example create a component
HandlePushNotification
that will wrap your stack<Stack>
Something like that :
And in your initial component :
You cannot use the
useDispatch
from a non-React function or custom hook, e.g. it can’t be called from within thesaveNotificationResponse
function.You can use the
store
object to directly dispatch actions to the store.The alternative is to create a React component that is rendered under the Redux
Provider
component such that it can access the Redux context.Example: