30

I am currently using react-navigation to do stack- and tab- navigation.

Is it possible to re-render a component every time the user navigates to specific screens? I want to make sure to rerun the componentDidMount() every time a specific screen is reached, so I get the latest data from the server by calling the appropriate action creator.

What strategies should I be looking at? I am pretty sure this is a common design pattern but I failed to see documented examples.

James
  • 3,597
  • 11
  • 41
  • 76

6 Answers6

55

If you are using React Navigation 5.X, just do the following:

import { useIsFocused } from '@react-navigation/native'

export default function App(){

    const isFocused = useIsFocused()

    useEffect(() => {
        if(isFocused){
            //Update the state you want to be updated
        }
    }, [isFocused])

}

The useIsFocused hook checks whether a screen is currently focused or not. It returns a boolean value that is true when the screen is focused and false when it is not.

Harsh Patel
  • 6,334
  • 10
  • 40
  • 73
  • 1
    Just saying, thanks for sharing `isFocused` but this does not show a way to rerender anything and thus, can't be the accepted answer. I can't find a way to rerender the view with it. I had to ask the question once more [here](https://stackoverflow.com/questions/63793666/how-to-rerender-a-component-in-react-navigation-when-focus-happen) – Dimitri Kopriwa Sep 08 '20 at 12:14
  • Well, I think there was a mistake on your part regarding the functioning of the code I talked about. This code is for you to know and update any state when the screen is FOCUSED, this code does not force a rendering. – Guilherme Trivilin Sep 08 '20 at 12:35
  • The question was about `re-render` (first word of the question), I finally ended up using `key` on a component` and `setMyKey(Math.random())` – Dimitri Kopriwa Sep 08 '20 at 12:38
  • Every status update on a functional component forces a re-rendering, so it worked! Good! – Guilherme Trivilin Sep 08 '20 at 13:40
  • 2
    I still think you should show how to re-render as this is the top choice when googling the question. – Dimitri Kopriwa Sep 08 '20 at 17:30
  • There, explained in the next comment. – Guilherme Trivilin Sep 08 '20 at 17:37
  • 1
    There is an issue with this code, this is called both when screen focussed or blurrs, which may not be required if the code is resource intensive (like an api call) – Abu Talha Danish Oct 23 '20 at 21:34
5

React Navigation lifecycle events quoted from react-navigation

React Navigation emits events to screen components that subscribe to them. There are four different events that you can subscribe to: willFocus, willBlur, didFocus and didBlur. Read more about them in the API reference.


Let's check this out,

With navigation listeners you can add an eventlistener to you page and call a function each time your page will be focused.

const didBlurSubscription = this.props.navigation.addListener(
  'willBlur',
  payload => {
    console.debug('didBlur', payload);
  }
);

// Remove the listener when you are done
didBlurSubscription.remove();

Replace the payload function and change it with your "refresh" function.

Hope this will help.

Maxence Machu
  • 330
  • 1
  • 14
3

You can also use also useFocusEffect hook, then it will re render every time you navigate to the screen where you use that hook.

useFocusEffect(()=> {
    your code
})
  • nice one! however you need it like this: `useFocusEffect( useCallback(() => { /* ... */ }, []) );` , source: https://reactnavigation.org/docs/use-focus-effect/ – Cagri Jan 19 '23 at 21:05
1

At the request of Dimitri in his comment, I will show you how you can force a re-rendering of the component, because the post leaves us with this ambiguity.

If you are looking for how to force a re-rendering on your component, just update some state (any of them), this will force a re-rendering on the component. I advise you to create a controller state, that is, when you want to force the rendering, just update that state with a random value different from the previous one.

0

Add a useEffect hook with the match params that you want to react to. Make sure to use the parameters that control your component so it rerenders. Example:

export default function Project(props) {
    const [id, setId] = useState(props?.match?.params?.id);
    const [project, setProject] = useState(props?.match?.params?.project);

    useEffect(() => {
        if (props.match) {
            setId(props.match?.params.id);
            setProject(props.match?.params.project);
        }
    }, [props.match?.params]);
   
......
Martlark
  • 14,208
  • 13
  • 83
  • 99
-1

To trigger a render when navigating to a screen.

import { useCallback } from "react"; 
import { useFocusEffect } from "@react-navigation/native";  

// Quick little re-render hook       
function useForceRender() {
    const [value, setValue] = useState(0);
    return [() => setValue(value + 1)];
}

export default function Screen3({ navigation }) {
  const [forceRender] = useForceRender();

  // Trigger re-render hook when screen is focused
  // ref: https://reactnavigation.org/docs/use-focus-effect
  useFocusEffect(useCallback(() => { 
    console.log("NAVIGATED TO SCREEN3")
    forceRender();
  }, []));
}

Note:

"@react-navigation/native": "6.0.13",
"@react-navigation/native-stack": "6.9.0",
user1160006
  • 533
  • 4
  • 12