Reputation:
I want my header icon to show count (every unread notification is count ++). From my Notification component I want to pass to the header in my Navigator a prop with the count number. All I can find so far are solutions for react navigation <5 (setParams and the like doesnt work with >5) and I am using 6. How do I do it?
const App = () => {
const [notifications, setNotifications] = useState([]);
useEffect(() => {
const notifications = await API.fetch();
let count= 0;
notifications.map(notification => {
if (notification.isRead === false) count ++;
})
// ---> send count to header in Navigator to be shown
}, [])
}
const MyTabs = (props) => {
const navigation = useNavigation();
return (
<Tab.Navigator
screenOptions={{
headerRight: (props) => {
return (
<TouchableOpacity onPress={() => navigation.navigate("Notifications")}>
<Ionicons name="notifications" size={24} color="black"/>
</TouchableOpacity>
)}
}}
>
</Tab.Navigator>
);
}
Edit:
const MyStack = () => {
const navigation = useNavigation();
return (
<Stack.Navigator>
<Stack.Group>
<Stack.Screen name="Tabs" options={({route}) => ({
headerShown: false,
})}>
{(props) => <MyTabs {...props} />}
</Stack.Screen>
<Stack.Screen
name="Notifications"
options={{
headerShown: true, headerLeft: () => (
<Button onPress={() => navigation.goBack()} title="go back"
/>
),
}}>
{(props) => <NotificationsScreen {...props}/>}
</Stack.Screen>
</Stack.Group>
</Stack.Navigator>
<NavigationContainer>
<MyStack />
</NavigationContainer>
//NavigationContainer is rendered inside App
Upvotes: 0
Views: 1717
Reputation: 655
I think what you are looking for is using the Navigation State
through the useNavigationState()
hook.
Look at that documentation, specifically at this section about triggering a re-render. You could send that information when you call the navigation.navigate()
.
Nevertheless, this is probably the wrong way of doing this. Using the navigation state to store your app information not related to the navigation is not safe (and even maybe an anti-pattern).
There are better ways of sharing a state over different components across your app and you could use one of them. I suggest using ContextAPI for decoupling the state from your components for this case as Redux is almost overkill.
For an even simpler approach, you could use a derived state from your notifications
such as:
const App = () => {
const [notifications, setNotifications] = useState([]);
const [unreadNotificationsCount, setUnreadNotificationsCount] = useState(0);
useEffect(() => {
const notifications = await API.fetch();
const newUnreadNotifications = notifications.filter((notification) => !notification.isRead);
setUnreadNotificationsCount(newUnreadNotifications.length)
}, []);
return (
<>
<Header unreadNotifications={unreadNotificationsCount} />
</>
);
}
Also, there are other things that you could take care of:
useEffect
is not considered a good pattern. You could call it outside of the useEffect
.Array.map()
is used to transform one array into another with the same size. If you just want to iterate over, use the Array.forEach()
count
to the Header. React is a "Reactive" framework. If you change that data into a state, all places that depend on that state will update. You can have that with some "global state" lib such as Redux or with ContextAPI (that is inside React)Upvotes: 2