react.js用于与父节点通信的自定义事件

问题描述 投票:61回答:6

我正在制作和监听正常的DOM CustomEvents以与父节点进行通信:

在孩子:

  var moveEvent = new CustomEvent('the-graph-group-move', { 
    detail: {
      nodes: this.props.nodes,
      x: deltaX,
      y: deltaY
    },
    bubbles: true
  });
  this.getDOMNode().dispatchEvent(moveEvent);

在父母:

componentDidMount: function () {
  this.getDOMNode().addEventListener("the-graph-group-move", this.moveGroup);
},

这有效,但有一种特定于React的方式会更好吗?

reactjs
6个回答
36
投票

如上所述:

React的方法是通过props显式地将回调传递给子节点 - 。在React中没有支持冒泡的自定义事件。

反应式编程抽象是正交的:

通过观察者模式编程交互系统很难并且容易出错,但仍然是许多生产环境中的实现标准。我们提出了一种逐步弃用观察者以支持反应式编程抽象的方法。多个库层帮助程序员顺利地将现有代码从回调迁移到更具声明性的编程模型。

React理念基于Command模式:

enter image description here

参考


3
投票

还有一个我发现的,这是非常合理的,特别是如果从父母到孩子的钻孔已经变得很麻烦。他称之为不太简单的沟通。这是链接:

https://github.com/ryanflorence/react-training/blob/gh-pages/lessons/04-less-simple-communication.md


3
投票

你可以写一个简单的服务,然后使用它

/** eventsService */
module.exports = {
  callbacks: {},

  /**
   * @param {string} eventName
   * @param {*} data
   */
  triggerEvent(eventName, data = null) {
    if (this.callbacks[eventName]) {
      Object.keys(this.callbacks[eventName]).forEach((id) => {
        this.callbacks[eventName][id](data);
      });
    }
  },

  /**
   * @param {string} eventName name of event
   * @param {string} id callback identifier
   * @param {Function} callback
   */
  listenEvent(eventName, id, callback) {
    this.callbacks[eventName][id] = callback;
  },

  /**
   * @param {string} eventName name of event
   * @param {string} id callback identifier
   */
  unlistenEvent(eventName, id) {
    delete this.callbacks[eventName][id];
  },
};

示例(触发相同)

import eventsService from '../../../../services/events';
export default class FooterMenu extends Component {
  componentWillMount() {
    eventsService
      .listenEvent('cart', 'footer', this.cartUpdatedListener.bind(this));
  }

  componentWillUnmount() {
    eventsService
      .unlistenEvent('cart', 'footer');
  }

  cartUpdatedListener() {
    console.log('cart updated');
  }
}

2
投票

将状态分配给客户端的中央存储[Redux],然后将“调度”状态重新发送到商店就像观察者模式一样。发布/订阅的方式只会因为连接道具/事件路径的显式(脆弱?)开销而变得更糟。通过层次结构来破解React提供了臭味的上下文(提供者模式)或可观察的库。像引入新装饰器@observable的MobX,或引入新模板语法“v-if”的Vue。无论如何,事件是DOM和javascript事件循环工作的主要方式,为什么不呢?我认为撒旦主义者做到了。大声笑


1
投票

一个可能的解决方案,如果你绝对必须求助于ReactJs应用程序中的Observer模式,你可以劫持一个正常的事件。例如,如果您希望删除键导致标记为删除的<div>,您可以让<div>侦听将由customEvent调用的keydown事件。陷阱身上的keydown并在选定的customEvent上发送<div> keydown事件。分享,以防它有助于某人。


1
投票

你可以通过上下文传递回调来冒泡事件:[CodePen]

import React, {Component, PropTypes} from 'react';

class EventContext extends Component {
  static contextTypes = {
    onMyEvent: PropTypes.func
  };
  static childContextTypes = {
    onMyEvent: PropTypes.func.isRequired
  };
  static propTypes = {
    onMyEvent: PropTypes.func.isRequired
  };
  getChildContext() {
    let {onMyEvent} = this.props;
    return {
      onMyEvent: (...args) => {
        // stop propagation if handler returns false
        if (onMyEvent(...args) !== false) {
          // bubble the event
          this.context.onMyEvent && this.context.onMyEvent(...args);
        }
      }
    };
  }
  render() {
    return this.props.children;
  }
}

class MyComponent extends Component {
  static contextTypes = {
    onMyEvent: PropTypes.func
  };
  render() {
    let {onMyEvent} = this.context;
    return <button onClick={onMyEvent}>Click me</button>;
  }
}

export default <EventContext onMyEvent={e => console.log('grandparent got event: ', e)}>
  <EventContext onMyEvent={e => console.log('parent got event: ', e)}>
    <MyComponent/>
  </EventContext>
</EventContext>;
© www.soinside.com 2019 - 2024. All rights reserved.