使用 react-native-navigation 时如何在显示组件时触发事件?

How to trigger an event when a component is shown when using react-native-navigation?

我正在使用带有 react-native-navigation 的 react-native。我想在显示组件时重新加载数据。当用户单击选项卡导航按钮时显示该组件。

我应该使用 React 生命周期事件还是在 react-native-navigation 中有什么可以在用户导航回组件时触发功能?

我正在使用 redux,我不确定它是否可以提供帮助?

此问题涉及 onDisplay,这似乎正是我要找的。但是我找不到任何关于它的官方文档 - https://github.com/wix/react-native-navigation/issues/130

覆盖 componentWillMount 生命周期方法: https://facebook.github.io/react/docs/component-specs.html#mounting-componentwillmount 或者只是将功能放在 render 方法中

这是我最终使用的:

export default class RootNavigator extends React.Component {
  state = {currentScreen: null}

  _onNavigationStateChange(prevState, newState, action) {
    // const currentScreen = getCurrentRouteName(currentState)
    // const prevScreen = getCurrentRouteName(prevState)
    // console.debug('onNavigationStateChange currentScreen=', currentScreen,
    //   'prevScreen=', prevScreen, 'action.routeName=', action.routeName)
    console.debug('onNavigationStateChange action.routeName=', action.routeName)
    this.setState({currentScreen: action.routeName})
  }

  render() {
    return <RootStackNavigator onNavigationStateChange={this._onNavigationStateChange.bind(this)}
      screenProps={{currentScreen: this.state.currentScreen}}/>;
  }

与屏幕上的 componentDidUpdate() 相结合(它可能会或可能不会执行某些操作,具体取决于 screenProps 的 currentScreen)。

注意:我不知道 what/where getCurrentRouteName() 是什么,它给了我错误,所以我不使用它,直接使用 action.routeName

有关更多信息和讨论,请参阅 https://github.com/react-community/react-navigation/issues/2371 and https://github.com/react-community/react-navigation/issues/51#issuecomment-323536642

将其作为 'callIfBackToThisRoute'...

export default ( props, call ) => {
    if( !props.navigation ) throw 'I need props.navigation'
    const thisRoute = props.navigation.state.routeName;
    props.navigation.addListener(
        'willFocus',
        payload => {
            if( payload.state.routeName == thisRoute) call(props)
        }
    );
}

并在您的组件中使用它...

componentDidMount() {
    const { doIt } = this.props;
    doIt()
    callIfBackToThisRoute(
        this.props,
        (props) => doIt()
    )
}

我喜欢 Bruno Reis 提出的解决方案。我调整了我的使其更简单。

class Whatever extends Component {
    componentDidMount(){
        this.load()
        this.props.navigation.addListener('willFocus', this.load)
    }
    load = () => {
        ...
    }

}

对于RNN v3,经过多次尝试,我终于找到了正确的方法:

  componentDidMount() {
    this.navigationEventListener = Navigation.events().bindComponent(this);
  }

  componentWillUnmount() {
    if (this.navigationEventListener) {
      this.navigationEventListener.remove();
    }
  }

  componentDidAppear() {   // Lazy loading data for RNN
    if (this.state.routes.length === 0) {
      this.getData();
    }
  }

关键是,事件监听器的绑定是必须的,否则不会触发componentDidAppear()和componentDidDisappear()

当前接受的答案建议使用 react-navigation 解决方案,而不是 react-native-navigation (RNN),所以我会继续并给出我的两分钱。

正如 Stephen Liu 在他的回答中指出的那样,RNN 提供 screen lifecycle methods 在组件出现 (componentDidAppear) 和消失 (componentDidDisappear) 时触发。

Stephen 的回答适用于 class 组件,但是在挂钩时代我更喜欢函数组件。所以这就是如何在函数组件中使用 RNN 的屏幕生命周期方法:

import React, { useEffect } from 'react'
import { Navigation } from 'react-native-navigation'

const MyComponent = ({ componentId }) => {

  useEffect(() => {
    const navListener = Navigation.events().bindComponent(this, componentId)

    // remove the listener during cleanup
    return () => {
      navListener.remove()
    }
  }, [componentId])

  this.componentDidAppear = () => {
    // do stuff when component appears
  }

  this. componentDidDisappear = () => {
    // do stuff when component disappears
  }

}

重要MyComponent 需要一个 componentId 道具,如果它是注册的 RNN 屏幕或模态 (Navigation.registerComponent),它会自动注入.您也可以手动将其从屏幕组件向下传递给您需要的子组件。

奖金:useComponentDidAppear挂钩

我在我的项目中经常使用 RNN 的 componentDidAppear,所以我制作了一个自定义挂钩,以便在我的函数组件中非常轻松地重用它:

export const useComponentDidAppear = (componentId, callback) => {
  useEffect(() => {
    const navListener = Navigation.events().bindComponent(this, componentId)
    return () => {
      navListener.remove()
    }
  }, [componentId])

  this.componentDidAppear = () => {
    callback()
  }
}

// then use it like this
const SomeScreen = ({ componentId }) => {

  useComponentDidAppear(componentId, () => {
    // do stuff when the component appears!
  })

}

documentation中显示可以这样添加焦点事件:

import React, { useEffect } from 'react'

const MyComponent = ({ navigation }) => {

    useEffect(() => {
        const unsubscribe = navigation.addListener('focus', () => {
            // do something
            console.log('Hello World!')
        });
        return unsubscribe;
    }, [navigation]);

    return (
        <View>
            <Text>MyComponent</Text>
        </View>
    )
}

export default MyComponent

我在自己的一个项目中遇到过同样的情况,使用 useFocusEffect hook by react navigation 来解决

有关更多信息,您可以参考有关此内容的文档

https://reactnavigation.org/docs/function-after-focusing-screen#triggering-an-action-with-the-usefocuseffect-hook