Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-navigation: Is it possible to pass a callback to children (e.g.changeHandler)?

What I've been trying is to pass a callback into a screen.

Here is an excerpt of my experimentation...

export default class Test extends React.Component {
    constructor(props) {
        super(props);
    };

    handleOnPress(data){
    //How do we pass this callback to "Home" or "Sub"?
    }

    render() {
        const Navigator = StackNavigator({
            Home: {screen: Home},
            Sub:  {screen: Sub}
        });
        let data = {blah:"blah blah"};

        return (<Navigator screenProps={data} />);
    }
}

In this example, I can get this.props.screenProps.blah in both Home and Sub. I assumed that being able to pass a prop would mean being able to pass a call back too, but I feel like I wasn't right.

Has anyone encountered this issue?

Any advice will be appreciated.

like image 856
Hiroki Avatar asked Nov 27 '17 06:11

Hiroki


People also ask

Does react Navigation use reanimated?

React Navigation related packages include @react-navigation/drawer , @react-navigation/stack , @react-navigation/bottom-tabs and @react-navigation/material-top-tabs use react-native-gesture-handler and react-native-reanimated for smooth gestures and animations.

What is callback in react?

The React useCallback Hook returns a memoized callback function. Think of memoization as caching a value so that it does not need to be recalculated. This allows us to isolate resource intensive functions so that they will not automatically run on every render.


2 Answers

If you just want to pass a callback to a child, you could specify in your render as a prop too:

<Navigator callback={this.handleOnPress} {/*And any other props you want to pass*/} />

And then in your Home or Sub class to trigger the callback as you probably expect

class Home extends React.Component {
    //...
    somefunction = () => {
        this.props.callback();
    }
}

This is what I am using in my code right now.

Though if you want to pass it to only either one of Home or Sub, this here is probably your answer: https://github.com/react-community/react-navigation/issues/935

const mapNavigationStateParamsToProps = (SomeComponent) => {
    return class extends Component {
        static navigationOptions = SomeComponent.navigationOptions; // better use hoist-non-react-statics
        render() {
            const {navigation: {state: {params}}} = this.props
            return <SomeComponent {...params} {...this.props} />
        }
    }
}

EDIT: In my case, my handler was an arrow function written like so:

handleOnPress = (data) => {
    //Do something here
}

It is so that I do not have to deal with .bind()s

FINAL SOLUTION by OP: Looks like StackNavigator requires props to be passed as screenProps, so, render function becomes:

render() {
    const Navigator = StackNavigator({
        Home: {screen: Home},
        Sub:  {screen: Sub}
    });
    let props = {
        data: "data",
        handleOnPress: () => this.handleOnPress()
    };

    return (<Navigator screenProps={props} />);
}
like image 65
ionizer Avatar answered Nov 10 '22 07:11

ionizer


passing a callback through react native navigation params is not recommended, this may cause the state to freeze (to not to update correctly). The better solution here would be using an EventEmitter, so the callback stays in the Screen1 and is called whenever the Screen2 emits an event.

Screen 1 code :

import DeviceEventEmitter from "react-native"

DeviceEventEmitter.addListener("event.testEvent", (eventData) => 
callbackYouWantedToPass(eventData)));

Screen 2 code:

import DeviceEventEmitter from "react-native"

DeviceEventEmitter.emit("event.testEvent", {eventData});

useEffect(() => {
    return () => {
        DeviceEventEmitter.removeAllListeners("event.mapMarkerSelected")
    };
}, []);
like image 42
George Fean Avatar answered Nov 10 '22 08:11

George Fean