Issue: I have a context wrapped around my entire app but I need an additional context for a single drawer screen and its sub screens & components.
DataProvider
is used by the entire App.
I have created a context to be used solely by the 'component' A I.e Screen A in the Drawer Navigator and its children(A sub screen) in Stack Navigator.
What has been done thus far:
Read docs and proceeded to wrap the entirety of the app with both context but considering just a subset of the drawer navigator and screen actually needs the AContext, I need to wrap just the screens / components that only needs it to prevent unnecessary re-renders for screens and components that doesn't require the context in the first place.
Any suggestion on how to proceed in this case or is it negligible?
Here's my App.js code:
const DrawerNavigator = () => {
return (
<Drawer.Navigator
initialRouteName=
screenOptions={({ navigation }) => ({
headerTitle: "",
}
)}
>
<Drawer.Screen
name="A"
component={A}
options={{
// freezeOnBlur: true,
}}
/>
<Drawer.Screen
name="B"
component={B}
options={{
freezeOnBlur: true,
}}
/>
<Drawer.Screen
name="C"
component={C}
options={{
freezeOnBlur: true,
}}
/>
</Drawer.Navigator>
)
};
export default function App() {
return (
<>
<DataProvider>
<AProvider>
<NavigationContainer>
<Stack.Navigator
screenOptions={({ navigation }) => ({
headerTitle: "",
})}
>
<Stack.Screen
name="HOME"
component={DrawerNavigator}
options={{ headerShown: false }}
/>
<Stack.Screen
name="ASubScreen"
component={ASubScreen}
options={{
/>
<Stack.Screen
name="D"
component={D}
options={{ headerTitle: "" }}
/>
<Stack.Screen
name="E"
component={E}
options={{ headerTitle: "" }}
/>Ï
</Stack.Navigator>
</NavigationContainer>
<ConsentModal />
</AProvider>
</DataProvider>
<StatusBar style="dark" />
<Toast />
</>
);
}
Here's the context code:
import React, { useEffect, useState } from "react";
export const AContext = React.createContext();
export const PayEProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
return (
<AContext.Provider
value={{
currentUser,
setCurrentUser
}}
>
{children}
</AContext.Provider>
);
};
Depending on what the AContext
value is or what the AProvider
provider component needs to handle and update it may be negligible, but it's always a good coding practice from a design/implementation to limit the scope of variables as much as possible. In other words, only lift the state/context/etc as high up the app structure as is necesssary.
With React-Navigation Screen
components I believe you have a couple basic options:
Create a screen component that renders the Context provider and the actual screen component, all on the component
prop.
const ASubScreenLayout = (props) => {
...
return (
<AProvider>
...
<ASubScreen {...props} />
...
</AProvider>
);
};
export default function App() {
return (
<>
<DataProvider>
<NavigationContainer>
<Stack.Navigator
screenOptions={({ navigation }) => ({
headerTitle: "",
})}
>
...
<Stack.Screen
name="ASubScreen"
component={ASubScreenLayout}
options={{ ... }}
/>
...
</Stack.Navigator>
</NavigationContainer>
<ConsentModal />
</DataProvider>
<StatusBar style="dark" />
<Toast />
</>
);
}
Use the children
render prop function, which is basically the above solution just inlined.
export default function App() {
return (
<>
<DataProvider>
<NavigationContainer>
<Stack.Navigator
screenOptions={({ navigation }) => ({
headerTitle: "",
})}
>
...
<Stack.Screen
name="ASubScreen"
options={{ ... }}
>
{(props) => (
<AProvider>
<ASubScreen {...props} />
</AProvider>
)}
</Stack.Screen>
...
</Stack.Navigator>
</NavigationContainer>
<ConsentModal />
</DataProvider>
<StatusBar style="dark" />
<Toast />
</>
);
}