구성 요소가 통신하도록하는 여러 가지 방법이 있습니다. 일부는 사용 사례에 적합 할 수 있습니다. 여기 내가 아는 유용한 것들의 목록이있다.
반응
부모 / 아동 직접 커뮤니케이션
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
여기서 자식 구성 요소는 부모가 제공 한 콜백을 값으로 호출하고 부모는 자식이 부모의 값을 제공 할 수 있습니다.
앱의 기능 / 페이지를 구축하는 경우 콜백 / 상태 ( container
또는 라고도 함 smart component
)를 관리하는 단일 부모가 있고 모든 자식은 상태를 유지하지 않고 부모에게만보고하는 것이 좋습니다. 이렇게하면 부모의 상태를 필요한 모든 어린이에게 쉽게 "공유"할 수 있습니다.
문맥
React Context를 사용하면 구성 요소 계층의 루트에서 상태를 유지할 수 있으며 모든 중간 구성 요소에 소품을 전달할 필요없이 매우 깊게 중첩 된 구성 요소 에이 상태를 쉽게 주입 할 수 있습니다.
지금까지 컨텍스트는 실험적인 기능 이었지만 React 16.3에서 새로운 API를 사용할 수 있습니다.
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
소비자가 render prop / children 함수 패턴을 사용하고 있습니다
자세한 내용은 이 블로그 게시물 을 확인하십시오.
React 16.3 이전 에는 매우 유사한 API를 제공하고 이전 컨텍스트 API를 사용하는 react-broadcast 를 사용하는 것이 좋습니다 .
포털
일반적인 부모 / 자식과 같이 간단한 구성 요소와 통신하기 위해 2 개의 구성 요소를 서로 가깝게 유지하려는 경우 포털을 사용하지만이 두 구성 요소가 DOM에서 부모 / 자식 관계를 갖기를 원하지 않습니다. 시각적 / CSS 제약 조건 (z-index, opacity ...와 같은)을 의미합니다.
이 경우 "포털"을 사용할 수 있습니다. 포털을 사용하는 다른 반응 라이브러리가 있으며 일반적으로 모달에 사용됩니다 , 팝업, 툴팁에 사용됩니다 ...
다음을 고려하세요:
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
내부에서 렌더링 될 때 다음 DOM을 생성 할 수 있습니다 reactAppContainer
.
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
자세한 내용은 여기
슬롯
슬롯을 어딘가에 정의한 다음 렌더 트리의 다른 위치에서 슬롯을 채 웁니다.
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
이것은 채워진 컨텐츠가 사용자가 정의한 슬롯에 렌더링된다는 점을 제외하고는 포털과 약간 유사하지만, 포털은 일반적으로 새로운 DOM 노드 (종종 문서의 하위)를 렌더링합니다.
체크는 반응-슬롯 채우기 라이브러리를
이벤트 버스
React 문서에 명시된 바와 같이 :
부모-자식 관계가없는 두 구성 요소 간의 통신을 위해 고유 한 글로벌 이벤트 시스템을 설정할 수 있습니다. componentDidMount ()에서 이벤트를 구독하고 componentWillUnmount ()에서 구독을 취소하고 이벤트를 수신하면 setState ()를 호출하십시오.
이벤트 버스를 설정하는 데 사용할 수있는 많은 것들이 있습니다. 리스너의 배열을 만들 수 있으며 이벤트 게시시 모든 리스너가 이벤트를 수신합니다. 또는 EventEmitter 또는 PostalJs 와 같은 것을 사용할 수 있습니다
유량
유량 는 기본적으로 이벤트 수신기이며, 이벤트 수신자는 상점입니다. 상태가 React 외부에서 관리된다는 점을 제외하면 기본 이벤트 버스 시스템과 유사합니다.
독창적 인 Flux 구현은 이벤트 소싱을 해키 방식으로 시도하는 것처럼 보입니다.
리덕스 는 이벤트 소싱에서 가장 가까운 Flux 구현으로 시간 여행 기능과 같은 많은 이벤트 소싱 이점을 제공합니다. React에 엄격하게 연결되어 있지 않으며 다른 기능적 뷰 라이브러리와 함께 사용할 수도 있습니다.
Egghead의 Redux 비디오 튜토리얼 은 정말 좋으며 내부적으로 어떻게 작동하는지 설명합니다 (실제로는 간단합니다).
커서
커서는 ClojureScript / Om 에서 나오며 React 프로젝트에서 널리 사용됩니다. React 외부의 상태를 관리 할 수 있으며 구성 요소 트리에 대해 알 필요없이 여러 구성 요소가 상태의 동일한 부분에 대한 읽기 / 쓰기 액세스 권한을 갖도록합니다.
ImmutableJS , React-cursors 및 Omniscient를 포함한 많은 구현이 존재합니다.
2016 편집 : 사람들은 커서가 작은 응용 프로그램에서는 잘 작동하지만 복잡한 응용 프로그램에서는 잘 확장되지 않는다는 데 동의합니다. Om Next에는 더 이상 커서가 없습니다 (초기에는 개념을 도입 한 것은 Om입니다)
느릅 나무 건축
느릅 나무 아키텍처는 아키텍처가 사용할 수 있도록 제안 느릅 나무 언어 . Elm이 ReactJS가 아니더라도 Rem에서도 Elm 아키텍처를 수행 할 수 있습니다.
Redux의 저자 인 Dan Abramov는 React를 사용하여 Elm 아키텍처를 구현했습니다 .
Redux와 Elm은 정말 훌륭하며 프론트 엔드에서 이벤트 소싱 개념을 강화하여 시간 여행 디버깅, 실행 취소 / 다시 실행, 재생을 허용합니다 ...
Redux와 Elm의 주요 차이점은 Elm이 상태 관리에 대해 훨씬 더 엄격한 경향이 있다는 것입니다. Elm에서는 로컬 구성 요소 상태 또는 마운트 / 마운트 후크를 가질 수 없으며 모든 DOM 변경은 글로벌 상태 변경으로 트리거되어야합니다. Elm 아키텍처 는 단일 불변 객체 내에서 모든 상태 를 처리 할 수있는 확장 가능한 접근 방식을 제안하는 반면, Redux 는 단일 불변 객체에서 상태의 대부분 을 처리하도록 초대하는 접근 방식을 제안 합니다.
Elm의 개념 모델은 매우 우아하고 아키텍처가 큰 앱에서 잘 확장 될 수 있지만 실제로 마운트하거나 입력 한 후 입력에 초점을 맞추거나 기존 라이브러리와 통합하는 등 간단한 작업을 수행하기에는 더 어렵거나 보일러 플레이트가 더 많이 포함될 수 있습니다. 명령형 인터페이스 (예 : JQuery 플러그인) 관련 문제 .
또한 Elm 아키텍처에는 더 많은 코드 상용구가 포함됩니다. 장황하거나 작성하기가 복잡하지는 않지만 Elm 아키텍처는 정적으로 유형이 지정된 언어에 더 적합하다고 생각합니다.
FRP
RxJS, BaconJS 또는 Kefir와 같은 라이브러리를 사용하여 구성 요소 간 통신을 처리하는 FRP 스트림을 생성 할 수 있습니다.
예를 들어 Rx-React를 시도 할 수 있습니다
이 libs를 사용하는 것은 ELM 언어가 신호 와 함께 제공하는 것을 사용하는 것과 매우 유사하다고 생각합니다 .
CycleJS 프레임 워크는 ReactJS를 사용하지 않고 vdom을 사용 합니다 . Elm 아키텍처와 많은 유사점을 공유하지만 (vdom 후크를 허용하므로 실제 생활에서 사용하기가 더 쉽습니다) 함수 대신 RxJ를 광범위하게 사용하며 FRP를 함께 사용하려는 경우 좋은 영감의 원천이 될 수 있습니다 반응. CycleJs Egghead 비디오 는 작동 방식을 이해하는 것이 좋습니다.
CSP
CSP (Communicating Sequential Processes)는 현재 널리 사용되지만 (주로 Go / goroutines 및 core.async / ClojureScript로 인해) JS-CSP 와 함께 javascript에서도 사용할 수 있습니다 .
James Long은 React와 함께 사용하는 방법을 설명하는 비디오 를 만들었습니다.
사 가스
saga는 "프로세스 관리자"라고도하는 DDD / EventSourcing / CQRS 세계에서 제공되는 백엔드 개념입니다. 그것은 redux-saga 프로젝트에 의해 대중화되고 있으며 , 주로 부작용 (예 : API 호출 등)을 처리하기 위해 redux-thunk를 대체합니다. 대부분의 사람들은 현재 부작용에 대해서만 서비스를 제공한다고 생각하지만 실제로는 구성 요소를 분리하는 것에 관한 것입니다.
사가는 결국 플럭스 액션을 내기 때문에 완전히 새로운 통신 시스템보다 Flux 아키텍처 (또는 Redux)에 대한 칭찬입니다. widget1과 widget2가 있고 이들을 분리하려는 경우 widget1에서 widget2를 대상으로하는 조치를 실행할 수 없습니다. 따라서 widget1은 자신을 대상으로하는 작업 만 실행하도록하고 saga는 widget1 작업을 수신하고 widget2를 대상으로하는 작업을 전달할 수있는 "백그라운드 프로세스"입니다. saga는 두 위젯 간의 연결 지점이지만 위젯은 분리되어 있습니다.
관심이 있으시면 여기 에서 내 대답을 살펴보십시오.
결론
서로 다른 스타일을 사용하는 동일한 작은 앱의 예를 보려면이 저장소 의 분기를 확인하십시오 .
장기적으로 최상의 옵션이 무엇인지 모르지만 Flux가 이벤트 소싱처럼 보이는 방식이 정말 좋습니다.
이벤트 소싱 개념을 모르는 경우이 교육적인 블로그를 살펴보십시오. Apache Samza로 데이터베이스를 내부로 돌리면 Flux가 왜 좋은지 이해해야합니다. (FRP에도 적용될 수 있음) )
커뮤니티는 가장 유망한 Flux 구현이 Redux 이며 핫 리로드 덕분에 매우 생산적인 개발자 경험을 점진적으로 허용 할 것이라고 동의합니다 . Bret Victor 's Inventing on Principle 비디오 의 인상적인 라이브 코딩 이 가능합니다!