如何为可重用组件组织 Redux 状态?

How to organize Redux state for reusable components?

TL;DR: 如果可重用组件有一些复杂的逻辑来管理其自身的状态(想想:带有自动完成器、表情符号等的 facebook 评论文本区域)如何一个使用 store、actions 和 reducer 来管理分布在整个网站上的该组件的多个实例的状态?

考虑官方 redux 存储库中的 real-world example。 其中有:

假设我真的希望 all 状态在 Redux 中。

特别是,我希望每个 RepoPage 和 UserPage 上的每个列表的状态都由 Redux 管理。这已经在例子中被一个聪明的 three-level 深树解决了:

我感觉这三个级别也分别对应:组件类型,parent类型,parentid。

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

特别是,我想知道如何实施解决方案,其中:

(我很高兴使用 Redux 的一些扩展,它仍然使用 reducer,但不想使用 "just keep it in React local state",出于这个问题的目的)

我目前的研究:

我将尝试解释受 Elm lang 启发并已移植到 Typescript 的想法之一:

假设我们有一个非常简单的组件,其状态如下

interface ComponentState {
   text: string
}

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

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

interface ResetAction {
    type: 'RESET_VALUE'
}

这 2 个操作的类型联合(请查看 Typescript 的可区分联合):

type ComponentAction = SetAction | ResetAction;

Reducer 应具有以下签名:

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

现在"embed"这个简单的组件在一个更大的组件中,我们需要在父组件中封装数据模型:

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

因为 redux 中的动作类型需要全局唯一,我们不能为 Component 实例分派单个动作,因为它将由两个实例处理。其中一个想法是使用以下技术将单个组件的操作包装到父操作中:

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

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

父操作联盟将具有以下签名:

type ParentComponentAction = Instance1ParentAction | Instance2ParentAction;

而这项技术最重要的事情 - parent reducer:

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

使用区分联合还为父和子减速器提供了类型安全。