부모 노드와 통신하기위한 react.js 커스텀 이벤트


84

나는 CustomEvent부모 노드와 통신하기 위해 일반 DOM을 만들고 듣고 있습니다 .

어린이 :

  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 전용 방법이 있습니까?


6
React 방식은 props를 통해 명시 적으로 자식에게 콜백을 전달하는 것 <Child onCustomEvent={this.handleCustomEvent} />입니다. React에서 버블 링이있는 사용자 지정 이벤트는 지원되지 않습니다.
andreypopp 2014

14
그렇다면 이벤트를 올리는 대신 콜백을 아래로 버블 링 하시겠습니까? 합리적인 것 같습니다.
forresto 2014

22
@forresto는 풍자, +1 사랑
디미타르 크리스토프

12
나는 냉소적이지 않았다.
forresto 2014

5
모범 사례를 설정하는 것과 실행 가능한 패턴을 방지하는 것입니다. DOMEvents를 사용하여 합성 이벤트를 버블 링하고 전파하는 twitter.github.io/flight 와 같은 극명한 대조를 이룹니다 .
Dimitar Christoff 2014

답변:


47

위에서 언급 한대로 :

React 방식은 props를 통해 명시 적으로 자식에게 콜백을 전달하는 것입니다. React에서 버블 링이있는 사용자 지정 이벤트는 지원되지 않습니다.

반응 형 프로그래밍 추상화는 직교합니다.

관찰자 패턴을 사용하여 대화 형 시스템을 프로그래밍하는 것은 어렵고 오류가 발생하기 쉽지만 여전히 많은 프로덕션 환경에서 구현 표준입니다. 우리는 반응 형 프로그래밍 추상화를 위해 관찰자를 점차적으로 비난하는 접근 방식을 제시합니다. 여러 라이브러리 레이어는 프로그래머가 기존 코드를 콜백에서보다 선언적인 프로그래밍 모델로 원활하게 마이그레이션하는 데 도움이됩니다.

React 철학은 대신 명령 패턴을 기반으로합니다.

여기에 이미지 설명 입력

참고 문헌


8
React에서 사용자 지정 합성 이벤트가 지원되지 않는 이유에 관심이 있습니다. 단순히 구현되지 않았거나 그렇지 않은 이유에 대한 유효한 설계 결정이 있습니까? 이벤트는 goto 문처럼 유해한 것으로 간주됩니까?
Michael Bylstra

4
@MichaelBylstra 사용자 정의 이벤트는로 인해 눈살을 찌푸리게하는 고전적인 문제 : a class of debugging problems where you don't know what triggers some code because of a long chain of events triggering other events. 명령 패턴단방향 데이터 흐름은 (가) 철학 반응이다.
Paul Sweatte 2015-08-13

2
컴포넌트가 React 컨텍스트 (Redux, React Router 등 모두 컨텍스트를 사용)를 통해 조상이 주입 한 Datastore와 통신한다는 사실을 고려할 때, 자식이 컨텍스트의 어떤 함수를 통해 조상에게 다시 전화를 걸어야한다고 말하는 것은 완전히 가짜입니다. 관용적 반응. Redux "dispatch"를 "action"객체로 호출하는 것과 컨텍스트에서 "event handler"를 "event"객체로 호출하는 것 사이에는 실제적인 차이가 없습니다.
Andy

1
다른 이벤트를 트리거하는 긴 이벤트 체인은 일부 사람들이 Redux를 사용하는 방식에서 매우 일반적입니다 (예 : redux-saga 광기)
Andy

요점은 알지만 질문이 있습니다. 여러 아키텍처에서 원활하게 작동하는 것을 목표로하는 UI-Kit 라이브러리를 구축한다고 가정 해 보겠습니다. 알 수없는 아키텍처에 대해 아무것도 가정 할 수 없기 때문에 일부 구성 요소는 사용자 지정 이벤트를 전달해야 할 수 있습니다. React의 엄격한 가정은 큰 문제를 야기합니다. 여기서 문제를 확인할 수 있습니다 ( custom-elements-everywhere.com ) : React는 사용자 지정 이벤트를 제대로 처리 할 수없는 유일한 라이브러리입니다. 어쩌면, 나는 무언가를 놓치고 어떤 제안이라도 매우 감사 할 것입니다.
7uc4

7

간단한 서비스를 작성하고 사용할 수 있습니다.

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

4

컨텍스트를 통해 전달 된 콜백을 통해 이벤트를 버블 링 할 수 있습니다. [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

특히 부모에서 자식으로 구멍을 뚫는 것이 이미 번거 롭다면 매우 합리적이라고 생각한 또 다른 것이 있습니다. 그는 그것을 덜 단순한 의사 소통이라고 불렀습니다. 링크는 다음과 같습니다.

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


이것은 기본적으로 "관찰자 패턴 구현"이라고 말합니다. 나는 OP에 대한 Michael Bylstra의 의견에 동의하며, Less Simple Communication에서 언급 된 문제를 "드릴링 구멍"이라고 설명합니다. 버블 링없이 콜백을 전달해도 1 레벨 이상의 깊은 구조를 처리하지 못합니다.
ericsoco 2015

3

가능한 해결책 은 ReactJs 앱에서 Observer 패턴에 절대적으로 의존 해야하는 경우 일반 이벤트를 가로 챌 수 있습니다. 예를 들어, <div>삭제 <div>로 표시된를 삭제 키로 인해 발생 시키려면 customEvent에 의해 호출되는 keydown 이벤트를 수신하도록 할 수 있습니다 . 본문에 keydown을 트랩하고 customEvent선택한에 keydown 이벤트를 전달합니다 <div>. 누군가에게 도움이되는 경우 공유합니다.


3

클라이언트에 상태를 배포 한 후 저장소에 '파견'상태를 백업하는 중앙 저장소 [Redux]도 관찰자 패턴과 같습니다. 게시 / 구독을 수행하는 방법은 props / events 경로를 연결하는 명시적인 (취약한?) 오버 헤드로 인해 더 나빠질뿐입니다. 계층 구조를 해킹하기 위해 React는 악취가 나는 컨텍스트 (제공자 패턴) 또는 관찰 가능한 라이브러리를 제공합니다. 새로운 데코레이터 @observable을 소개하는 MobX 또는 새로운 템플릿 구문 "v-if"를 도입하는 Vue와 같습니다. 이벤트는 어쨌든 DOM 및 자바 스크립트 이벤트 루프가 작동하는 기본 방법입니다. 사탄 숭배자들이 그랬다고 생각합니다. Lol


1

나는이 질문이 지금 꽤 오래되었다는 것을 알고 있지만이 답변은 여전히 ​​누군가를 도울 수 있습니다. 선언적 사용자 지정 이벤트를 추가하는 React 용 JSX pragma를 작성했습니다 : jsx-native-events .

기본적으로 onEvent<EventName>패턴을 사용하여 이벤트를 감시합니다.

<some-custom-element onEventSomeEvent={ callback }></some-custom-element>
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.