【问题标题】:How to Listen for Events in children components in React Native?如何在 React Native 中监听子组件中的事件?
【发布时间】:2018-04-30 06:03:00
【问题描述】:

我想在我的 React Native 应用程序中实现从父组件到子组件的事件侦听器,我使用 StackNavigator 作为路由器。

如何监听顶级/父组件中发生的事件?

【问题讨论】:

  • 您可以发表问题并自己回答,不要在问题中回答。

标签: reactjs react-native react-navigation dom-events eventemitter


【解决方案1】:

只需使用 React Native 的 DeviceEventEmitter。从父组件中发出您的事件,如下所示:

DeviceEventEmitter.emit('eventKey', {name:'John', age:23});

在子组件中监听事件

componentDidMount(){
      //add listener
      this.eventListener = DeviceEventEmitter.addListener('eventKey',this.handleEvent);
}

handleEvent=(event)=>{
 //Do something with event object
}

componentWillUnmount(){
      //remove listener
      this.eventListener.remove();
}

【讨论】:

  • 我喜欢它,比通过​​ StackNavigator 的 screenProps 传递变量要好得多。谢谢!
  • 重要的是还要确保删除componentWillUnmount() 事件上的侦听器。这应该被标记为答案
【解决方案2】:

最好的方法不是使用 EventEmitter 以我目前的经验(7 个月后这个问题)是使用 Redux 作为状态持有者,您可以创建将通过组件父子组件传递消息的变量,然后连接获取变量(状态)的组件会立即发生变化。

我决定使用Rematch,它是 Redux 的缩小版,我得到了非常好的结果。它迫使我删除所有的 EventEmitters 并使用调度方法来更新将在连接的组件中更新的变量(状态)。

【讨论】:

    【解决方案3】:

    我一直在研究如何在 React Native 中从父组件向子组件发出和侦听事件,在尝试了不同的方法后,我认为分享我的工作方式可能会很好。

    在您的父组件(在我的例子中为 App.js)中,导入 EventEmitter 库:

    import EventEmitter from 'EventEmitter';
    

    创建事件发射器的变量实例:

    export default class App extends Component {
    
    ...
    
      componentWillMount() {
        this.eventEmitter = new EventEmitter();
      }
    
    ...
    
    }
    

    然后,当有事情发生时发出事件:

    this.eventEmitter.emit('Event-Name', {args});
    

    当我使用 StackNavigator 作为路由器时,我必须将我的 eventEmitter 变量传递给孩子们的意见:

    const routes = {
      ChildView1: {
        screen: ChildComponent1
      },
      ChildView2: {
        screen: ChildComponent2
      },
      ...
    };
    
    const AppNavigator = StackNavigator(
      {
        ...routes,
      },
      {
        initialRouteName: 'ChildView1',
        headerMode: 'none',
      /*
       * Use modal on iOS because the card mode comes from the right,
       * which conflicts with the drawer example gesture
       */
        mode: Platform.OS === 'ios' ? 'modal' : 'card',
      }
    );
    
    /* Here is the magic for the children views */
    
    render(){
      return (
        <AppNavigator screenProps={this.eventEmitter} />
      );
    }
    

    好的,现在我们已经为子视图提供了事件监听器,让我们在其中一个子组件中进行调用:

    export default class ChildComponent1 extends Component {
    
      ComponentWillMount(){
    
        this.eventEmitter = this.props.screenProps;
    
        this.eventEmitter.addListener('Event-Name', ()=>{
    
          // Do something
    
        });
    
      }
    
      ...
    
    }
    

    这就是我为子组件完成事件侦听器的方式,希望对其他人有所帮助。如果您有更好的实现,请分享/评论它。

    【讨论】:

    • 另一种我认为可行的方法。您可以将父组件的事件保存在本地状态中,然后将其作为道具传递给子组件,这样每当事件发生时,它将更改父组件中的状态,并且将在您可以处理的地方调用子组件的 componentWillReceiveProps 方法。跨度>
    【解决方案4】:

    最简单的方法:

    1) 在您的 app.js 中创建监听器(初始启动文件): 示例:

    (new NativeEventEmitter()).addListener('loggedIn',() => {
            setAuth(true);
        });
    

    2) 只需从任何孩子发出:(new NativeEventEmitter()).emit('loggedIn');

    希望它对某人有用!)

    【讨论】:

      【解决方案5】:

      在跟踪事件的来源或被侦听的位置时,使用事件发射器可能会有点混乱。

      就像您通过screenProps={this.eventEmitter} 将事件发射器向下传递给孩子一样(这就是您本质上在做的事情),为什么不直接传递您的孩子可以用来在其父级上启动操作的实际函数。这可能是最有反应的做事方式。

      添加额外的事件侦听器可能并不理想,因为它会在某些时候影响性能。

      【讨论】:

      • 听起来不错,但我无法让它工作。我已经传递了一个空父变量,然后在子视图中为此设置了一个函数,但是当我尝试在父级上调用它时,它仍然是空/未定义的。
      【解决方案6】:

      我遵循了 OP 使用 redux 的想法,它对我来说效果很好。这是代码...

      actionTypes.js:

      export const TRIGGER_REQUEST_SUBMIT = "TRIGGER_REQUEST_SUBMIT";
      export const ACKNOWLEDGE_REQUEST_SUBMIT = "ACKNOWLEDGE_REQUEST_SUBMIT";
      

      eventActions.js:

      import * as types from "./actionTypes";
      
      export function triggerRequestSubmit() {
        return function(dispatch) {
          dispatch({ type: types.TRIGGER_REQUEST_SUBMIT });
        };
      }
      
      export function acknowledgeRequestSubmit() {
        return function(dispatch) {
          dispatch({ type: types.ACKNOWLEDGE_REQUEST_SUBMIT });
        };
      }
      

      eventReducer.js:

      import * as types from "../actions/actionTypes";
      import initialState from "./initialState";
      
      export default function eventReducer(state = initialState.event, action) {
        switch (action.type) {
          case types.TRIGGER_REQUEST_SUBMIT:
            return { ...state, shouldSubmitRequest: true };
          case types.ACKNOWLEDGE_REQUEST_SUBMIT:
            return { ...state, shouldSubmitRequest: false };
          default:
            return state;
        }
      }
      

      不要忘记在你的 root-reducer/index.js 中注册 reducer

      initialState.js:

      export default {
        event: {
          shouldSubmitRequest: false
        }
      };
      

      在 child 中的使用(使用 redux 连接并通过 state 获取 shouldSubmitRequest,通过 dispatch 确认RequestSubmit):

       useEffect(() => {
          if (shouldSubmitRequest) {
            console.log("shouldSubmitRequest triggered in Request");
            acknowledgeRequestSubmit();
          }
        }, [shouldSubmitRequest]);
      

      在父调用 triggerRequestSubmit(); (连接到 redux 以获取该方法)

      【讨论】:

      • 也可以使用 ContextAPI。我还没有尝试过,很想看到有人解释这样做的方法。
      猜你喜欢
      • 2015-05-07
      • 1970-01-01
      • 2016-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-07
      • 2021-07-06
      • 1970-01-01
      相关资源
      最近更新 更多