Sự kiện tùy chỉnh react.js để giao tiếp với các nút cha


84

Tôi đang tạo và lắng nghe các DOM thông thường CustomEventgiao tiếp với các nút cha:

Ở trẻ em:

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

Trong cha mẹ:

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

Điều này hoạt động, nhưng có cách nào dành riêng cho React sẽ tốt hơn không?


6
Cách React sẽ là chuyển các lệnh gọi lại cho trẻ em một cách rõ ràng thông qua đạo cụ - <Child onCustomEvent={this.handleCustomEvent} />. Không có hỗ trợ cho các sự kiện tùy chỉnh w / bubble trong React.
andreypopp

14
Vì vậy, bong bóng các cuộc gọi lại xuống thay vì các sự kiện lên? Có vẻ hợp lý.
forresto

22
@forresto thích sự mỉa mai, +1
Dimitar Christoff

12
Tôi không bị mỉa mai.
forresto

5
đó là một thứ thiết lập một phương pháp hay nhất, một thứ khác để ngăn chặn một mô hình khả thi. hoàn toàn trái ngược với nói, twitter.github.io/flight - sử dụng DOMEvents để tạo bong bóng và tuyên truyền các sự kiện tổng hợp.
Dimitar Christoff

Câu trả lời:


47

Như đã nói ở trên:

Cách React sẽ là chuyển các lệnh gọi lại cho trẻ em một cách rõ ràng thông qua đạo cụ -. Không có hỗ trợ cho các sự kiện tùy chỉnh w / foam trong React.

Phần trừu tượng lập trình phản ứng là trực giao:

Việc lập trình các hệ thống tương tác bằng mô hình quan sát là khó và dễ xảy ra lỗi nhưng vẫn là tiêu chuẩn thực hiện trong nhiều môi trường sản xuất. Chúng tôi trình bày một cách tiếp cận để dần dần phản đối những người quan sát mà ủng hộ các lập trình trừu tượng phản ứng. Một số lớp thư viện giúp các lập trình viên di chuyển mã hiện có một cách suôn sẻ từ các lệnh gọi lại sang một mô hình lập trình khai báo hơn.

Thay vào đó, triết lý của React dựa trên Command pattern:

nhập mô tả hình ảnh ở đây

Người giới thiệu


8
Tôi quan tâm đến việc tại sao không có hỗ trợ cho các sự kiện tổng hợp tùy chỉnh trong React. Có phải chỉ đơn giản là chúng chưa bao giờ được triển khai, hay có một quyết định thiết kế hợp lệ tại sao chúng lại không ?. Các sự kiện có được coi là có hại như câu lệnh goto không?
Michael Bylstra

4
Sự kiện @MichaelBylstra tuỳ chỉnh được tán thành do một vấn đề cổ điển : a class of debugging problems where you don't know what triggers some code because of a long chain of events triggering other events. Mẫu lệnh với luồng dữ liệu một chiều là triết lý của React.
Paul Sweatte

2
Xem xét thực tế là các thành phần giao tiếp với Datastore được đưa vào bởi tổ tiên thông qua ngữ cảnh React, (Redux, React Router, v.v. tất cả đều sử dụng ngữ cảnh), hoàn toàn không có thật khi nói rằng một đứa trẻ gọi lại tổ tiên thông qua bất kỳ hàm nào trên ngữ cảnh là không. thành ngữ React. Không có sự khác biệt thực tế nào giữa việc gọi Redux là "công văn" với một đối tượng "hành động" và gọi một "trình xử lý sự kiện" trên ngữ cảnh với một đối tượng "sự kiện".
Andy

1
Chuỗi dài của các sự kiện kích hoạt các sự kiện khác là khá phổ biến trong cách một số người sử dụng Redux (ví dụ như Redux-saga điên rồ)
Andy

Tôi hiểu ý, nhưng tôi có một câu hỏi. Giả sử rằng người ta sẽ xây dựng một thư viện UI-Kit nhằm mục đích hoạt động liền mạch trên nhiều kiến ​​trúc. Một số thành phần có thể cần gửi các sự kiện tùy chỉnh vì chúng tôi không thể giả định gì về một kiến ​​trúc không xác định. Giả định nghiêm ngặt của React dẫn đến một vấn đề lớn. Bạn có thể kiểm tra vấn đề tại đây ( custom-elements-everywhere.com ): React là thư viện duy nhất không thể xử lý các sự kiện tùy chỉnh đúng cách. Có lẽ, tôi bỏ lỡ điều gì đó và bất kỳ đề xuất nào sẽ rất được đánh giá cao.
7uc4,

7

bạn có thể viết một dịch vụ đơn giản và sau đó sử dụng nó

/** 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];
  },
};

ví dụ (tương tự cho việc kích hoạt)

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');
  }
}

4

Bạn có thể làm nổi bật các sự kiện thông qua các lệnh gọi lại được truyền lại qua các ngữ cảnh: [CodePen]

import * as React from 'react';

const MyEventContext = React.createContext(() => {});

const MyEventBubbleContext = ({children, onMyEvent}) => {
  const bubbleEvent = React.useContext(MyEventContext);
  const handleMyEvent = React.useCallback((...args) => {
    // stop propagation if handler returns false
    if (onMyEvent(...args) !== false) {
      // bubble the event
      bubbleEvent(...args);
    }
  }, [onMyEvent]);
  return (
    <MyEventContext.Provider value={handleMyEvent}>
      {children}
    </MyEventContext.Provider>
  );
};

const MyComponent = () => (
  <MyEventBubbleContext onMyEvent={e => console.log('grandparent got event: ', e)}>
    <MyEventBubbleContext onMyEvent={e => console.log('parent got event: ', e)}>
      <MyEventContext.Consumer>
        {onMyEvent => <button onClick={onMyEvent}>Click me</button>}
      </MyEventContext.Consumer>
    </MyEventBubbleContext>
  </MyEventBubbleContext>
);

export default MyComponent;

3

Có một cái khác mà tôi thấy cũng khá hợp lý, đặc biệt là nếu việc khoan lỗ từ cha mẹ sang con cái đã trở nên cồng kềnh rồi. Ông gọi đó là giao tiếp ít đơn giản hơn. Đây là liên kết:

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


Về cơ bản, đây là câu nói "thực hiện mẫu Người quan sát". Tôi đồng ý với nhận xét của Michael Bylstra về OP, mô tả vấn đề được lưu ý trong Giao tiếp ít đơn giản là "lỗ khoan" ... mà không sủi bọt, chuyển lệnh gọi lại không xử lý cấu trúc sâu> 1 cấp.
ericsoco

3

Một giải pháp khả thi, nếu bạn nhất thiết phải sử dụng mẫu Observer trong ứng dụng ReactJs, bạn có thể chiếm quyền điều khiển một sự kiện bình thường. Ví dụ: nếu bạn muốn khóa xóa gây ra một sự <div>kiện được đánh dấu để xóa, bạn có thể <div>nghe sự kiện khóa xuống sẽ được gọi bởi customEvent. Bẫy phím xuống trên cơ thể và gửi một customEventsự kiện phím xuống trên phần đã chọn <div>. Chia sẻ trong trường hợp nó giúp một ai đó.


3

Một cửa hàng trung tâm [Redux] phân phối trạng thái cho khách hàng, trạng thái 'điều phối' sau đó sao lưu tới cửa hàng cũng giống như một mẫu quan sát. Một cách thực hiện xuất bản / đăng ký chỉ tồi tệ hơn vì các đường dẫn kết nối đạo cụ / sự kiện rõ ràng (giòn?). Để tấn công thông qua hệ thống phân cấp, React cung cấp ngữ cảnh (mẫu nhà cung cấp) hoặc các thư viện có thể quan sát được. Như MobX giới thiệu trình trang trí mới @observable hoặc Vue giới thiệu cú pháp mẫu mới "v-if". Sự kiện là cách chính của DOM và vòng lặp sự kiện javascript hoạt động, vậy tại sao không? Tôi nghĩ các satanists đã làm điều đó. Cười lớn


1

Tôi nhận ra rằng câu hỏi này đã khá cũ cho đến nay, nhưng câu trả lời này vẫn có thể giúp ích cho ai đó. Tôi đã viết một pragma JSX cho React có thêm sự kiện tùy chỉnh khai báo: jsx-native-events .

Về cơ bản, bạn chỉ sử dụng onEvent<EventName>mẫu để xem các sự kiện.

<some-custom-element onEventSomeEvent={ callback }></some-custom-element>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.