플럭스 스토어 나 액션 (또는 둘 다)이 외부 서비스와 접촉해야합니까?


122

상점이 자체 상태를 유지하고 그렇게하면서 네트워크 및 데이터 저장 서비스를 호출 할 수있는 능력이 있다면 ...이 경우 작업은 멍청한 메시지 전달자 일뿐입니다.

-또는-

... 저장소는 작업에서 변경 불가능한 데이터의 멍청한 수신자 여야합니까 (작업은 외부 소스간에 데이터를 가져 오거나 보내는 작업입니까?이 인스턴스의 저장소는 뷰 모델 역할을하며 집계 / 필터링 할 수 있습니다.) 액션에 의해 공급 된 불변 데이터에 자체 상태 기반을 설정하기 전에 데이터.

나에게 그것은 (둘 다 혼합하기보다는) 하나 또는 다른 것이어야한다고 생각합니다. 그렇다면 왜 하나가 다른 것보다 선호 / 권장됩니까?


2
이 게시물이 힘 도움말 code-experience.com/...
마르쿠스 - IPSE

플럭스 패턴의 다양한 구현을 평가하는 사람들을 위해 Redux github.com/rackt/redux Stores는 현재 상태를 받아들이고 해당 상태의 새 버전을 방출하는 순수 함수로 구현되는 것을 적극 권장 합니다. 그것들은 순수한 기능이기 때문에 그들이 네트워크와 스토리지 서비스를 호출 할 수 있는지 여부에 대한 질문은 당신의 손에서 제거됩니다. 그들은 할 수 없습니다.
plaxdan

답변:


151

나는 플럭스 패턴이 두 가지 방식으로 구현되는 것을 보았고, 두 가지를 모두 수행 한 후 (처음에는 이전 접근 방식으로 진행) 저장소가 작업에서 데이터의 멍청한 수신자 여야하며 쓰기의 비동기 처리가 액션 크리에이터. ( 비동기 읽기는 다르게 처리 될 수 있습니다 .) 제 경험상 중요한 순서대로 다음과 같은 몇 가지 이점이 있습니다.

  1. 상점은 완전히 동기화됩니다. 이렇게하면 상점 로직을 훨씬 쉽게 따르고 테스트하기가 매우 쉬워집니다. 특정 상태로 상점을 인스턴스화하고 조치를 보내고 상태가 예상대로 변경되었는지 확인하기 만하면됩니다. 또한 유동적 인 핵심 개념 중 하나는 계단식 디스패치를 ​​방지하고 한 번에 여러 개의 디스패치를 ​​방지하는 것입니다. 상점이 비동기 처리를 할 때 이것은 매우 어렵습니다.

  2. 모든 액션 디스패치는 액션 제작자로부터 발생합니다. 상점에서 비동기 작업을 처리하고 상점의 작업 처리기를 동기식으로 유지하려는 경우 (플럭스 단일 발송 보장을 받기 위해해야 ​​함) 상점은 비동기에 대한 응답으로 추가 SUCCESS 및 FAIL 작업을 실행해야합니다. 처리. 대신 이러한 디스패치를 ​​액션 제작자에게 배치하면 액션 제작자와 상점의 작업을 분리하는 데 도움이됩니다. 또한 작업이 발송되는 위치를 파악하기 위해 상점 로직을 파헤칠 필요가 없습니다. 이 경우 일반적인 비동기 작업은 다음과 같을 수 있습니다 ( dispatch사용중인 플럭스 의 특징에 따라 호출 구문 변경 ).

    someActionCreator: function(userId) {
      // Dispatch an action now so that stores that want
      // to optimistically update their state can do so.
      dispatch("SOME_ACTION", {userId: userId});
    
      // This example uses promises, but you can use Node-style
      // callbacks or whatever you want for error handling.
      SomeDataAccessLayer.doSomething(userId)
      .then(function(newData) {
        // Stores that optimistically updated may not do anything
        // with a "SUCCESS" action, but you might e.g. stop showing
        // a loading indicator, etc.
        dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData});
      }, function(error) {
        // Stores can roll back by watching for the error case.
        dispatch("SOME_ACTION_FAIL", {userId: userId, error: error});
      });
    }
    

    그렇지 않으면 다양한 작업에 복제 될 수있는 논리를 별도의 모듈로 추출해야합니다. 이 예에서 해당 모듈은 SomeDataAccessLayer실제 Ajax 요청을 처리하는입니다.

  3. 액션 크리에이터가 덜 필요합니다. 이것은 큰 문제는 아니지만 가지고 있으면 좋습니다. # 2에서 언급했듯이 스토어에 동기식 작업 디스패치 처리가있는 경우 (그리고 그래야만하는 경우) 비동기 작업의 결과를 처리하기 위해 추가 작업을 실행해야합니다. 액션 생성자에서 디스패치를 ​​수행한다는 것은 단일 액션 생성자가 비동기 데이터 액세스 자체의 결과를 처리하여 세 가지 액션 유형을 모두 디스패치 할 수 있음을 의미합니다.


15
웹 API 호출 (액션 생성자 대 상점)의 원인이 성공 / 오류 콜백이 작업을 생성해야한다는 사실보다 덜 중요하다고 생각합니다. 따라서 데이터 흐름은 항상 액션-> 디스패처-> 저장-> 뷰입니다.
fisherwebdev 2014 년

1
실제 요청 로직을 API 모듈에 넣는 것이 더 좋고 / 쉽습니까? 따라서 API 모듈은 전달한 약속을 반환 할 수 있습니다. 액션 생성자는 초기 '보류 중'액션을 보낸 후 해결 / 실패에 따라 디스패치합니다. 남은 질문은 요청 상태가 저장 상태에 매핑되어야하는지 확실하지 않기 때문에 구성 요소가 이러한 '이벤트'를 수신하는 방법입니다.
백 데스크

@backdesk 바로 위의 예에서 제가하는 일입니다. 초기 보류 작업 ( "SOME_ACTION")을 전달하고 API를 사용하여 SomeDataAccessLayer.doSomething(userId)약속을 반환하는 요청 ( ) 을 만들고 두 .then함수에서 추가 작업을 전달합니다. 애플리케이션이 상태 상태에 대해 알아야하는 경우 요청 상태가 저장 상태에 매핑 될 수 있습니다. 이지도가 앱에 미치는 영향 (예 : 각 댓글에 개별 오류 상태, Facebook 또는 하나의 전역 오류 구성 요소가있을 수 있음)
Michelle Tilley

@MichelleTilley "플럭스의 핵심 개념 중 하나는 계단식 디스패치를 ​​방지하고 한 번에 여러 번의 디스패치를 ​​방지하는 것입니다. 상점이 비동기 처리를 수행 할 때 이것은 매우 어렵습니다." 그것이 제게 핵심 포인트입니다. 잘했다.

51

이 질문을 Facebook의 개발자들에게 트윗했고 Bill Fisher로부터받은 답변은 다음과 같습니다.

UI와 사용자의 상호 작용에 응답 할 때 액션 생성자 메서드에서 비동기 호출을 수행합니다.

그러나 시세 표시기 또는 사람이 아닌 다른 운전자가있는 경우 매장에서 전화를 걸면 더 효과적입니다.

중요한 것은 오류 / 성공 콜백에서 작업을 생성하여 데이터가 항상 작업에서 생성되도록하는 것입니다.


이것이 의미가 있지만 이유는 a call from store works better when action triggers from non-human driver 무엇입니까?
SharpCoder

@SharpCoder 라이브 티커 또는 이와 유사한 것이 있으면 실제로 작업을 수행 할 필요가 없으며 상점에서 수행 할 때 상점이 상태에 즉시 액세스 할 수 있으므로 코드를 적게 작성해야 할 것입니다. & 변화를 내 보낸다.
Florian Wendelborn

8

상점은 데이터 가져 오기 및 상점의 데이터가 업데이트되었음을 ​​구성 요소에 알리는 등 모든 작업을 수행해야합니다. 왜? 중요한 행동에 영향을주지 않고 가볍고 일회용이며 교체가 가능하기 때문입니다. 모든 중요한 동작과 기능은 상점에서 발생합니다. 이것은 또한 매우 유사하지만 다른 두 동작으로 복사되는 동작의 중복을 방지합니다. 상점은 진실 의 단일 소스입니다.

모든 Flux 구현에서 Actions는 기본적으로 객체로 변환 된 이벤트 문자열입니다. 전통적으로 "anchor : clicked"라는 이벤트가 있지만 Flux에서는 AnchorActions.Clicked로 정의됩니다. 대부분의 구현에는 실제로 수신하는 상점에 이벤트를 전달하는 별도의 Dispatcher 객체가있을 정도로 "멍청한"것입니다.

개인적으로 나는 별도의 Dispatcher 객체가없고 Action 객체가 자체적으로 디스패치를하는 Reflux의 Flux 구현을 좋아합니다.


편집 : Facebook의 Flux는 실제로 "액션 크리에이터"를 가져 와서 스마트 액션을 사용합니다. 또한 상점을 사용하여 페이로드를 준비합니다.

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27(27 행 및 28 행)

완료시 콜백은 이번에는 가져온 데이터를 페이로드로 사용하여 새 작업을 트리거합니다.

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

그래서 나는 그것이 더 나은 해결책이라고 생각합니다.


이 Reflux 구현은 무엇입니까? 들어 본 적이 없습니다. 당신의 대답은 흥미 롭습니다. 스토어 구현에 API 호출 등을 수행하는 로직이 있어야한다는 의미입니까? 나는 상점이 데이터를 받고 값을 업데이트해야한다고 생각했습니다. 특정 작업을 필터링하고 상점의 일부 속성을 업데이트합니다.
Jeremy D

Reflux는 Facebook의 Flux를 약간 변형 한 것입니다. github.com/spoike/refluxjs Stores는 애플리케이션의 전체 "모델"도메인을 관리하는 반면 , 작업 / 디스패처는 사물을 연결하고 붙이기 만합니다 .
Rygu 2014 년

1
그래서 나는 이것에 대해 좀 더 생각하고 내 질문에 (거의) 대답했습니다. 나는 (다른 사람들이 투표 할 수 있도록) 여기에 답변으로 추가했을 것입니다. 그러나 분명히 아직 답변을 게시 할 수있을만큼 stackoverflow에서 너무 업장이 부족합니다. 그래서 여기에 링크가 있습니다 : groups.google.com/d/msg/reactjs/PpsvVPvhBbc/BZoG-bFeOwoJ
plaxdan 2014 년

Google 그룹 링크에 감사드립니다. 정말 유익한 것 같습니다. 나는 또한 디스패처를 통과하는 모든 것을 더 좋아하고, 저장소의 정말 간단한 논리, 기본적으로 데이터를 업데이트하는 것이 전부입니다. @Rygu 역류를 확인하겠습니다.
Jeremy D

대체보기로 내 대답을 편집했습니다. 두 가지 해결책이 모두 가능한 것 같습니다. 나는 거의 확실하게 다른 것보다 Facebook의 솔루션을 선택할 것입니다.
Rygu 2014 년

3

나는 "멍청한"행동에 찬성하는 주장을 제공 할 것이다.

작업에서 뷰 데이터를 수집하는 책임을 둠으로써 작업을 뷰의 데이터 요구 사항에 연결합니다.

반대로, 사용자 의 의도 를 선언적으로 설명하는 일반 작업 또는 애플리케이션의 일부 상태 전환은 해당 작업에 응답하는 모든 Store가 해당 작업에 응답하는 모든 스토어를 구독 한보기에 맞게 특별히 조정 된 상태로 변환 할 수 있도록합니다.

이것은 더 많지만 더 작고 더 전문화 된 상점에 적합합니다. 나는이 스타일을 주장한다.

  • 이는 뷰가 스토어 데이터를 소비하는 방식에 더 많은 유연성을 제공합니다.
  • 뷰를 소비하는 뷰에 특화된 "스마트"스토어는 잠재적으로 많은 뷰가 의존하는 "스마트"액션보다 복잡한 앱에 대해 더 작고 덜 결합됩니다.

스토어의 목적은 뷰에 데이터를 제공하는 것입니다. "액션"이라는 이름은 그 목적이 내 응용 프로그램의 변경 사항을 설명하는 것임을 암시합니다.

백엔드 팀이 방금 출시 한 멋진 새 집계 데이터를 보여주는 기존 대시 보드보기에 위젯을 추가해야한다고 가정합니다.

"스마트"작업을 사용하면 새 API를 사용하기 위해 "대시 보드 새로 고침"작업을 변경해야 할 수 있습니다. 그러나 추상적 인 의미에서 "대시 보드 새로 고침"은 변경되지 않았습니다. 뷰의 데이터 요구 사항이 변경되었습니다.

"dumb"Actions를 사용하면 사용할 새 위젯에 대한 새 Store를 추가하고 "refresh-dashboard"Action 유형을 수신 할 때 새 데이터에 대한 요청을 전송하고이를 노출하도록 설정할 수 있습니다. 준비가되면 새 위젯. 뷰 레이어가 더 많거나 다른 데이터를 필요로 할 때 내가 변경하는 것이 그 데이터의 소스라는 것이 이해가됩니다.


2

gaeron의 flux-react-router-demo 에는 '올바른'접근 방식의 유용한 유틸리티 변형이 있습니다.

ActionCreator는 외부 API 서비스에서 promise를 생성 한 다음 promise와 3 개의 작업 상수를 dispatchAsync프록시 / 확장 디스패처 의 함수에 전달합니다 . dispatchAsync항상 첫 번째 액션 (예 : 'GET_EXTERNAL_DATA')을 전달하고 약속이 반환되면 'GET_EXTERNAL_DATA_SUCCESS'또는 'GET_EXTERNAL_DATA_ERROR'를 전달합니다.


1

Bret Victor의 유명한 비디오 Inventing on Principle 에서 볼 수있는 개발 환경과 비슷한 개발 환경을 원하는 경우 부작용없이 데이터 구조 내부의 작업 / 이벤트를 투영하는 멍청한 저장소를 사용해야합니다. 상점이 실제로 Redux 와 같이 동일한 전역 불변 데이터 구조의 구성원 인 경우에도 도움이 될 것 입니다.

여기에 더 많은 설명이 있습니다 : https://stackoverflow.com/a/31388262/82609

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