useNavigationState
useNavigationState is a hook which gives access to the navigation state of the navigator which contains the screen. It's useful in rare cases where you want to render something based on the navigation state.
Consider the navigator's state object to be internal and subject to change in a minor release. Avoid using properties from the navigation state state object except index and routes, unless you really need it. If there is some functionality you cannot achieve without relying on the structure of the state object, please open an issue.
It can be used in two ways.
Getting the navigation state by screen name
The hook accepts the name of the current screen or any of its parent screens as the first argument to get the navigation state for the navigator containing that screen. The second argument is a selector function that receives the full navigation state and can return a specific value from the state:
- Static
- Dynamic
import { useNavigationState } from '@react-navigation/native';
function CurrentRouteDisplay() {
const focusedRouteName = useNavigationState(
'Home',
(state) => state.routes[state.index]
);
return <Text>Current route: {focusedRouteName}</Text>;
}
import { useNavigationState } from '@react-navigation/native';
function CurrentRouteDisplay() {
const focusedRouteName = useNavigationState(
'Home',
(state) => state.routes[state.index]
);
return <Text>Current route: {focusedRouteName}</Text>;
}
The selector function helps to reduce unnecessary re-renders, so your screen will re-render only when that's something you care about. If you actually need the whole state object, you can do this explicitly:
const state = useNavigationState('Home', (state) => state);
Getting the current navigation state
You can also use useNavigationState without a screen name to get the navigation state for the current screen's navigator. In this case, it takes a selector function as the only argument:
const focusedRouteName = useNavigationState(
(state) => state.routes[state.index].name
);
This is often useful for re-usable components that are used across multiple screens.
This hook is useful for advanced cases and it's easy to introduce performance issues if you're not careful. For most of the cases, you don't need the navigator's state.
How is useNavigationState different from navigation.getState()?
The navigation.getState() function also returns the current navigation state. The main difference is that the useNavigationState hook will trigger a re-render when values change, while navigation.getState() won't. For example, the following code will be incorrect:
function Profile() {
const routesLength = navigation.getState().routes.length; // Don't do this
return <Text>Number of routes: {routesLength}</Text>;
}
In this example, even if you push a new screen, this text won't update. If you use the hook, it'll work as expected:
- Static
- Dynamic
import { useNavigationState } from '@react-navigation/native';
function useIsFirstRouteInParent() {
const route = useRoute();
const isFirstRouteInParent = useNavigationState(
(state) => state.routes[0].key === route.key
);
return isFirstRouteInParent;
}
function usePreviousRouteName() {
return useNavigationState((state) =>
state.routes[state.index - 1]?.name
? state.routes[state.index - 1].name
: 'None'
);
}
import { useNavigationState } from '@react-navigation/native';
function useIsFirstRouteInParent() {
const route = useRoute();
const isFirstRouteInParent = useNavigationState(
(state) => state.routes[0].key === route.key
);
return isFirstRouteInParent;
}
function usePreviousRouteName() {
return useNavigationState((state) =>
state.routes[state.index - 1]?.name
? state.routes[state.index - 1].name
: 'None'
);
}
So when do you use navigation.getState()? It's mostly useful within event listeners where you don't care about what's rendered. In most cases, using the hook should be preferred.
Using with class component
You can wrap your class component in a function component to use the hook:
class Profile extends React.Component {
render() {
// Get it from props
const { routesLength } = this.props;
}
}
// Wrap and export
export default function (props) {
const routesLength = useNavigationState((state) => state.routes.length);
return <Profile {...props} routesLength={routesLength} />;
}