2017-07-28 104 views
4

TL; DR:如果一个可复用组件具有一些复杂的逻辑来管理自己的状态(想一想:带有自动补全,表情符号等的Facebook注释文本框)如何使用存储,动作和缩减器来管理状态这个组件的多个实例遍布整个网站?如何组织可重用组件的Redux状态?

考虑官方的redux回购中的real-world example。 在这里面,我们有:

  • 一个RepoPage,它显示谁已经出演一个特别的回购协议的用户列表,
  • 一个UserPage,显示这是由特定用户
  • 一个List出演回购名单,这是足够通用的,它可以显示用户列表或回购,提供items和方式renderItem。特别是RepoPage使用User组件来显示为回购单元加星标的每个用户,并且UserPage使用Repo单元来显示每个加星标的回购单元。

假设我真的想要所有的状态在Redux中。

特别是,我希望每个RepoPage和UserPage上的每个List的状态由Redux管理。这已经在本例中的照顾,由一个聪明的三级深树:

  • 在顶层的关键说什么样的分量数据是(在本例中它被称为store.pagination
  • 则存在对于每个特定类型的上下文,其中,组件可以是(store.pagination.starredByUserstore.pagination. stargazersByRepo
  • 然后作为有独特的上下文有尽可能多的密钥的分支(store.pagination.starredByUser[login]store.pagination. stargazersByRepo[repo]

我FE el这三个级别也对应于:组件类型,父类型,父级id。

但是,我不知道如何扩展这个想法,以处理List组件本身有很多孩子的情况,在Redux中有一个值得追踪的状态。

我特别想知道如何在其中实现一个解决方案:

  • User组件保持不变
  • Repo组件有一个按钮,用于切换其背景颜色
  • 每个Repo的状态组件由Redux管理

(我很乐意使用一些扩展到终极版,仍然采用减速,但不想去“只是不停地在当地做出反应状态”,对于这个问题的目的)

我的研究至今

  • 它看起来像在Elm中Actions(消息)是可以以这种方式嵌套的代数数据类型,父组件可以解开消息的“外部信封”并将用于孩子的内部动作传递给子Reducer (更新)。
  • 由于在Redux中使用字符串作为动作类型的惯例,上述想法的自然翻译是使用前缀,而这似乎是prism(以前称为redux-elm)所做的: action.type由通过组件树指示路径的子字符串组成。 OTOH在this comment棱镜笔者tomkis解释说,榆树架构是终极版缺少的最重要的部分是行动的组成
  • 上述两种方法似乎是扩大在Reusing Reducer Logic
  • 描述方法的版本我没有充分把握redux-fly如何在内部工作,但它似乎使用有效负载而不是action.type通过其在store中的安装路径来标识组件实例,由于组件树由组件树手动构造的方式也对应组件树中的路径
  • WinAPI,在我看来,与Redux相似,如果你斜视,使用唯一的hWnd标识对于每一个控制,这使得它非常容易检查action是否适用于您,并决定您的州在store的哪个位置。
  • 上述想法很可能会导致Documentation suggestion/discussion: Reusing Reducer Logic中描述的内容,其中每种类型的组件都有自己的扁平子树,并由唯一的id索引。
  • 上面链接的链接描述的另一个想法是为特定类型的组件编写一个reducer,然后让父组件的reducer调用它(这也意味着,父类负责决定在哪里店子的状态所在地 - 再次,这似乎类似于榆树架构给我)
  • 一个很有趣的讨论More on reusability for custom components其中一个建议的细节改变一个类似于上面给出特别上述讨论
  • 包含用户nav的a proposition,以这种方式递归地组织存储树,即组件的状态是两种分支中的子树:一种用于私人东西,另一种用于子组件的“表格”,w这里每个子组件类都有它自己的“表”,并且每个子实例都有一个唯一键,该表中的状态是递归存储的。访问这些孩子的唯一密钥存储在“私人”部分。这与我想象的WinAPI非常相似:)
  • 另一个elm-inspired proposition来自同一个线程的用户sompylasar将使用包含儿童动作的动作作为“matrioshka”风格中的有效载荷,在我看来,它模仿代数类型构造函数嵌套在Elm中
  • redux-subspace被推荐用于棱镜的discussion about Global Actions,作为一种既受Elm启发又允许您采取全局行动的库。
+1

这里是redux-subspace的创建者。最近,我对“真实世界”示例进行了一次尝试,以及它如何使用孤立的组件进行查看。看看[回购](https://github.com/ioof-holdings/redux-subspace/tree/master/examples/real-world)或[沙箱](https://codesandbox.io/s/github/ioof-holdings/redux-subspace/tree/master/examples/real-world)如果你有兴趣。 –

回答

1

我将试图解释这是由榆树郎灵感,已经被移植到打字稿理念之一:

比方说,我们有以下的状态非常简单的组件

interface ComponentState { 
    text: string 
} 

组件可以通过以下2个动作来减少。

interface SetAction { 
    type: 'SET_VALUE', payload: string 
} 

interface ResetAction { 
    type: 'RESET_VALUE' 
} 

型工会对于那些2个行动(请看打字稿的识别联合):

type ComponentAction = SetAction | ResetAction; 

减速这个应该有THW以下签名:

function componentReducer(state: ComponentState, action: ComponentAction): ComponentState { 
    // code 
} 

我们“嵌入“在我们需要将数据模型封装在父组件中的这个较大组件中的这个简单组件:

interface ParentComponentState { 
    instance1: ComponentState, 
    instance2: ComponentState, 
} 

因为redux中的动作类型需要全局唯一,所以我们无法为组件实例分派单个动作,因为它将由两个实例处理。其中一个想法是包装单个部分的动作为母公司行动以下技术:

interface Instance1ParentAction { 
    type: 'INSTNACE_1_PARENT', 
    payload: ComponentAction, 
} 

interface Instance2ParentAction { 
    type: 'INSTNACE_2_PARENT', 
    payload: ComponentAction, 
} 

家长行动联盟将具有以下特征:

type ParentComponentAction = Instance1ParentAction | Instance2ParentAction; 

而且这项技术的最重要的事情 - 父缩减器:

function parentComponentReducer(state: ParentComponentState, action: ParentComponentAction): ParentComponentState { 
    switch (action.type) { 
     case 'INSTNACE_1_PARENT': 
      return { 
       ...state, 
       // using component reducer 
       instance1: componentReducer(state.instance1, action.payload), 
      }; 
     // 
    } 
} 

使用判别联盟另外给父母和孩子减速器的类型安全。

相关问题