1

Trying to set the header's title dynamically in React Navigation 6 but I keep getting a warning message:

Warning: Cannot update a component (NativeStackNavigator) while rendering a different component (CategoryMealsScreen)

My navigator stripped down:

import * as React from 'react'
import { Platform } from 'react-native'
import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'
import CategoryMealsScreen from '../screens/CategoryMealsScreen'
import colors from '../constants/colors'

const Stack = createNativeStackNavigator()

export default MealsNavigator = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator
        screenOptions={{
          headerStyle: {
            backgroundColor: Platform.OS === 'android' ? colors.primaryColor : '',
          },
          headerTintColor: Platform.OS === 'android' ? 'white' : colors.primaryColor,
        }}
      >
        <Stack.Screen
          name="CategoryMeals"
          component={CategoryMealsScreen}
          options={{ headerBackTitle: '' }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  )
}

how I'm setting title in the component:

  navigation.setOptions({
    title: selectedCategory.title,
  })

per the docs on Updating options with setOptions. The full component for reference:

import React from 'react'
import { View, StyleSheet, FlatList } from 'react-native'
import MealItem from '../components/MealItem'
import { CATEGORIES, MEALS } from '../data/dummy-data'

const CategoryMealsScreen = ({ navigation, route }) => {
  const catId = route.params.categoryId
  const selectedCategory = CATEGORIES.find(cat => cat.id === catId)
  const displayedMeals = MEALS.filter(mean => mean.categoryIds.indexOf(catId >= 0))

  // Issue falls here
  navigation.setOptions({
    title: selectedCategory.title,
  })

  const renderMealItem = ({ item }) => {
    return (
      <MealItem
        title={item.title}
        image={item.imageUrl}
        duration={item.duration}
        complexity={item.complexity}
        affordability={item.affordability}
        onSelectMeal={() => {
          navigation.navigate('MealDetail', {
            mealId: item.id,
          })
        }}
      />
    )
  }

  return (
    <View style={styles.container}>
      <FlatList
        keyExtractor={item => item.id}
        data={displayedMeals}
        renderItem={renderMealItem}
        style={{ width: '100%' }}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  screen: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 15,
  },
})

export default CategoryMealsScreen

Research:

Everything works in my Expo app but I'm unsure if the component sets the category ID depending on what's selected passed from props how do I dynamically set the title if I cannot set the title at the Stack Screen from the navigator?

DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127

1 Answers1

0

I'm no expert on this but I just encountered the same problem. I think it might be because you're telling React to change the NativeStackNavigator while you're rendering the screen.

instead of setting options={{ headerBackTitle: '' }} inside your navigator Stack.Screen, set it to: options={{headerShown:false}}

then inside your CategoryMealsScreen you can do whatever you want inside useEffect or useLayout Effect (doing it outside those will lead back to the error) like so:

useLayoutEffect(() => {
    navigation.setOptions({ headerShown: true, title: selectedCategory.title });

  }, [selectedCategory.title]);

Note that you'll have to import useEffect or useLayoutEffect from 'react' like so: import {useEffect, useLayoutEffect} from 'react'

You can learn more about useEffect vs useLayoutEffect here. This should work in react navigation v6, I don't know about other versions.