简体   繁体   中英

How can I change the header icon dynamically with React Navigation?

I'm working on a list with React Native, but when I perform a search by pressing the search icon set in the navigationOptions property I want the icon to change dynamically to another so the user can cancel the search. How can I change the icon dynamically by pressing the button?

static navigationOptions = ({navigation}) => ({
   headerTitle: 'POSTS',
   headerRight: (
     <Icon
      type="Ionicons"
      name="search"
      style={{color:"#FFFFFF", marginRight: 10}}
      size={20}
      onPress={navigation.getParam('openSearchModal')}
    />
  )
});

openSearchModal() {
   //my code is here
}

Application header

You can solve this problem by changing the status value.

  constructor(props){
    super(props);
    this.state={
      check : "search"
    }
  }

  static navigationOptions = ({navigation}) => ({
   headerTitle: 'POSTS',
   headerRight: (
     <Icon
      type="Ionicons"
      name={this.state.check === "search" ? "search" : "cancel"}
      style={{color:"#FFFFFF", marginRight: 10}}
      size={20}
      onPress={this.checkfunc(navigation)}
    />
  )
});

checkfunc = (navigation) => {
  if(this.state.check === "search") {
    this.setState({
      check : "cancel"
    });
    navigation.getParam('openSearchModal');
  }else{
    // your code here
  }
}

Are you new to react or react native?

You can actually achieve the mentioned objective by setting a state using Hook (quite new in react). Give the state a default icon name so that it will be used when the component first rendered.

const [searchButtonIcon, setSearchButtonIcon] = useState('icon-name')

Later on, you can set the search button to invoke a function which will update the state called searchButtonIcon during onPress . The code to update the state (if you are using Hooks) will be as follow.

setSearchButtonIcon('new-icon-name')

Note: You will need to update the value for the state to the correct icon name.

If you are not looking to use Hooks (only available in recent ReactJs) then you can use Redux to achieve the desired effect as well.

Old question but I just ran into this so I thought I would share what I had to do.

The official docs suggest that you set the header buttons using the hook "useLayoutEffect", since this is run before the screen is painted. However you are not able to change the header buttons after the content is loaded.

So instead you have to use the normal "useEffect" hook to allow the header button to be loaded at start, and dynamically changed as the state changes.

official docs show the example below: https://reactnavigation.org/docs/header-buttons/

function StackScreen() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={({ navigation, route }) => ({
          headerTitle: props => <LogoTitle {...props} />,
        })}
      />
    </Stack.Navigator>
  );
}

function HomeScreen({ navigation }) {
  const [count, setCount] = React.useState(0);

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerRight: () => (
        <Button onPress={() => setCount(c => c + 1)} title="Update count" />
      ),
    });
  }, [navigation]);

  return <Text>Count: {count}</Text>;
}

Addition to the code to make it dynamic a header button dynamically change:

function StackScreen() {
  return (
    <Stack.Navigator>
      <Stack.Screen
        name="Home"
        component={HomeScreen}
        options={({ navigation, route }) => ({
          headerTitle: props => <LogoTitle {...props} />,
        })}
      />
    </Stack.Navigator>
  );
}

function HomeScreen({ navigation }) {
  const [count, setCount] = React.useState(0);
  const [headerButton, setHeaderButton] = React.useState(false);
  React.useEffect(() => {
      navigation.setOptions({
      headerLeft: () => (<Text>{count}</Text>)
    });
  }, [navigation]);

  React.useLayoutEffect(() => {
    navigation.setOptions({
      headerRight: () => (
        <Button onPress={() => setCount(c => c + 1)} title="Update count" />
      ),
    });
  }, [navigation]);

  return <Text>Count: {count}</Text>;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM