2

I've thoroughly read the documentation on passing params between screens with React Navigation: https://reactnavigation.org/docs/params/

However, all of those examples only work if you are calling navigation.navigate manually and passing the params. For example:

<Button
  title="Done"
  onPress={() => {
    // Pass and merge params back to home screen
    navigation.navigate({
     name: 'Home',
     params: { post: postText },
     merge: true,
    });
  }}
/>

I have a screen with a back button, where I can call navigation.navigate and pass params on button press, like in the example above. However, the user can also swipe from the left to go back to the first screen on Android (and I'm assuming iOS as well).

So, my question:

Is there a way for me to pass the same data to the previous screen when the user swipes to go back (instead of pressing the back button)?

Ken White
  • 123,280
  • 14
  • 225
  • 444

1 Answers1

4

There might be a better way that I am unaware of. However, we can achieve this manually by preventing the default back action and handling this ourselves.

Suppose that you have a screen B and you want to swipe back to go to a screen Home and pass params to Home from B on that swipe action. Then, you can achieve this as follows.

function B({navigation}) {

  React.useEffect(() => navigation.addListener('beforeRemove', (e) => {
         
        // the navigation.navigate will fire beforeRemove which causes an infinite loop. we guard this here
        if (e.data.action.type === "NAVIGATE") {
          return
        }
        // Prevent default behavior of leaving the screen
        e.preventDefault();
        
        // navigate manually
        navigation.navigate({
            name: 'Home',
            params: { post: postText },
            merge: true,
        });        
        
   }), [navigation]);

  return ( ... )
}

Edit: The navigation.navigate fires the beforeRemove event again, obviously, which causes an infinite loop. We can guard this as shown above.

David Scholz
  • 8,421
  • 12
  • 19
  • 34
  • Thanks, I've actually already tried this - I get an error though: 'Uncaught error: Maximum call stack size exceeded' whenever I navigate back from screen B to screen A. Any ideas? – Ollie Clark May 01 '22 at 23:36
  • @OllieClark Ups, yes. I have fixed this. Check my updated answer. – David Scholz May 02 '22 at 00:13
  • Well that works! Thanks very much, although now I have a new problem - I'm trying to pass state from screen B to Home through params. On screen B, I have my state: `const [editName, setEditName] = useState('');` Then my input which manages the state: ` setEditName(text)} />` I know this works since I can console.log 'editName' and it will reflect whatever was typed. However, if I log 'editName' inside the function you provided it comes back as an empty string, like it's setting the state back to it's initial value before firing. – Ollie Clark May 02 '22 at 11:26
  • You need to provide `editName` in the dependency array of the `useEffect` or otherwise the updated value won't be available. Thus, the dependency array is `[navigation, editName]` – David Scholz May 02 '22 at 11:28
  • 1
    Seems to be doing the trick now, thanks a bunch! – Ollie Clark May 02 '22 at 20:36
  • The guard against the infinite loop is the trick to solving the "Maximum call stack" error. – Thomas Contreras Aug 04 '23 at 14:43