React-native-navigation: Discussion:[V2][Hooks] How to use bindComponent() of EventListener with a React Functional Component (convert from Class Component)

Created on 28 Jun 2019  ·  7Comments  ·  Source: wix/react-native-navigation

Issue Discussion

Hi, just providing some feedback based on my experience:

I am tried convert React Class Component to React Functional Component with Hooks. My project have used RNN V2 alongside lottie-react-native, which requires the componentDidAppear and componentDidDisappear events to handle animations each time the component appears/disappears on screen. And before I used Navigation.events().bindComponent(this) in React Class Component to subscribe to a component's events.

For Class-base, the solution was to use the bindComponent(this) method as explained in the V2 docs.

With Functional, however the bindComponent(this) does not work as expected. And I can't find anything which offers the same functionality in the V2 docs. Fortunately, I found something related in the #4295 comment.

Then, I made Cmd+click (Ctrl+click on Windows) perform a "Go To Definition" on the identifier under the cursor for bindComponent() function. In deep of node_modules/react-native-navigation, This function has been declared with 2 parameters as:

bindComponent(component: React.Component, componentId?: string): EventSubscription;

Finally, using this function with 2 parameters as declared solved the problem for React Functional Component with Hooks.

Steps to Reproduce / Code Snippets / Screenshots

Workaround for React Class Component

...
  componentDidMount() {
      // that are called on the component when it appears and disappears
      // (after it was bounded using Navigation.events().bindComponent(this)).
      this.navigationEventListener = Navigation.events().bindComponent(this);
    }
  }
  componentWillUnmount() {
      // Because a component is actually mounted as soon as it's part of a layout
      // -- but it is not always visible (for example, when another screen is pushed on top of it).
      // => Remove Listener after component is removed from DOM => component haven't been rendered
      this.navigationEventListener.remove();
    }
  }

  componentDidAppear() {
    // Re-play animation after paused by auto-disappearing component
    if (this.lottieAnimation) {
      this.lottieAnimation.play();
    }
  }

  componentDidDisappear() {
    // Stopping animation after disappearing
    if (this.lottieAnimation) {
      this.lottieAnimation.reset();
    }
  }
...

_Workaround for React Functional Component with Hooks_

...
    useEffect(() => {
        // that are called on the component when it appears and disappears
        // ***(after it was bounded using bindComponent() with 2 parameters)***
        const navigationEventListener = Navigation.events().bindComponent(this, componentId);
        return () => {
          // Because a component is actually mounted as soon as it's part of a layout
          // but it is not always visible (for example, when another screen is pushed on top of it).
          // => Remove Listener after component is removed from DOM => component haven't been rendered
          if (navigationEventListener) {
            navigationEventListener.remove();
          }
        };
      }
    });

    componentDidAppear = () => {
      // Re-play animation after paused by auto-disappearing component
      if (lottieAnimation) {
        lottieAnimation.play();
      }
    };

    componentDidDisappear = () => {
      // Stopping animation after disappearing
      if (lottieAnimation) {
        lottieAnimation.reset();
      }
    };
...

Environment

  • React Native Navigation version: 2.12.0
  • React Native version: 0.59.9
  • Platform(s) (iOS, Android, or both?): Both
  • Device info (Simulator/Device? OS version? Debug/Release?): ALL
🏚 stale

Most helpful comment

Use registerNavigationButtonPressedListener

e.g.

  useEffect(() => {
    const listener = Navigation.events().registerNavigationButtonPressedListener(
      () => {
        // do things
      }
    );
    return () => listener.remove();
  }, []);

All 7 comments

I just want to show again my workaround but its untested:
It is only for who concern about converting React Class Component to React Functional Component with Hooks, which have used alongside RNN V2
Replace:

this.navigationEventListener = Navigation.events().bindComponent(this);

With:

const navigationEventListener = Navigation.events().bindComponent(this, componentId);

Use registerNavigationButtonPressedListener

e.g.

  useEffect(() => {
    const listener = Navigation.events().registerNavigationButtonPressedListener(
      () => {
        // do things
      }
    );
    return () => listener.remove();
  }, []);

FYI I've just reported an issue on Android related with functional components using hooks.

The issue came up while using https://github.com/underscopeio/react-native-navigation-hooks

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you believe the issue is still relevant, please test on the latest Detox and report back. Thank you for your contributions.

The issue has been closed for inactivity.

const navigationEventListener = Navigation.events().bindComponent(this, componentId);

@tuanduongdn1504 what does this refer to in this line of code? Aren't we using functional components? I find that confusing.

registerNavigationButtonPressedListener

This does not trigger (in v3 at least)

Was this page helpful?
0 / 5 - 0 ratings