redux - 如何组织可重用组件的Redux状态?

标签 redux components code-reuse separation-of-concerns

TL; DR:在可重用的组件中,该组件具有一些用于管理其自身状态的复杂逻辑(例如:带有自动完成程序,表情符号等的Facebook注释文本区域),一个人如何使用存储,动作和简化器来管理多个实例的状态这个组成部分遍布整个网站吗?

考虑官方redux仓库中的real-world example
其中包含:


RepoPage,其中显示已为特定回购加注星标的用户列表,
UserPage,显示由特定用户加注星标的存储库列表
List,足够通用,它可以显示用户列表或存储库,只要提供itemsrenderItem的方式即可。特别地,RepoPage使用User组件显示每个给该存储库加注星标的用户,而UserPage使用一个Repo组件显示每个已加星标的存储库。


假设我真的希望所有状态都在Redux中。

特别是,我希望每个RepoPage和UserPage上每个List的状态都由Redux管理。在示例中,聪明的三层深树已经解决了这个问题:


在最高级别,键说明它是什么类型的组件数据(在示例中,它称为store.pagination
然后针对每种特定类型的上下文都有一个分支,组件可以在其中(store.pagination.starredByUserstore.pagination. stargazersByRepo
那么键和唯一上下文(store.pagination.starredByUser[login]store.pagination. stargazersByRepo[repo])一样多


我觉得这三个级别也对应于:组件类型,父类型,父ID。

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

我特别想知道如何实现以下解决方案:


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


(我很高兴使用Redux的一些扩展,这些扩展仍然使用reducer,但出于这个问题的目的,不想使用“仅将其保持在React local状态”)

到目前为止,我的研究:


看起来在Elm中,动作(消息)是代数数据类型,可以通过以下方式嵌套:父组件可以拆开消息的“外信封”,然后将用于子级的内部动作传递给子级简化器(更新程序)。
由于在Redux中使用字符串作为操作类型是惯例,因此上述想法的自然翻译是使用前缀,这似乎就是prism(以前称为redux-elm)所做的事情:< cc>由子字符串组成,这些子字符串告诉通过组件树的路径。棱镜作者tomkis在this comment中的OTOH解释说Redux缺少的Elm Architecture最重要的部分是动作的组合
以上两种方法似乎是Reusing Reducer Logic中描述的方法的扩展版本
我还没有完全掌握redux-fly在内部的工作方式,但是它似乎是使用有效负载而不是action.type通过action.type中的安装路径来标识组件实例的,该安装路径也对应于组件树中的路径由于它是由组件手动构建的方式
对我来说,如果看上去很Red,WinAPI与Redux非常相似,它为每个控件使用唯一的store标识符,这使得检查hWnd是否适合您并在< cc>。
上面的想法可能会导致Documentation suggestion/discussion: Reusing Reducer Logic 中描述的内容,其中每种类型的组件都有自己的通过唯一ID索引的平面子树。
在上面链接的链接线程中描述的另一个想法是为特定类型的组件编写一次reducer,然后让父组件的reducer调用它(这也意味着,父组件负责确定存储在哪个位置。定位了孩子的状态-对我来说,这似乎类似于Elm Architecture)
进行了非常有趣的讨论More on reusability for custom components,其中提案的详细信息与上述内容不同
特别是上面的讨论中,用户nav包含a proposition,以这种方式递归组织商店树,即组件的状态是两个分支中的子树:一个分支用于私有,另一个分支用于“表”。子组件,子组件的每个类都有其自己的“表”,子组件的每个实例在该表中都有唯一的键,其状态以递归方式存储。可以访问这些子代的唯一密钥存储在“专用”部分中。这确实类似于我想象的WinAPI :)
用户sompylasar的另一个elm-inspired proposition来自同一线程的操作是使用包含针对孩子的操作的操作作为“ matrioshka”样式的有效负载,在我看来,这模仿了代数类型构造函数在Elm中的嵌套方式
redux-subspace中,建议使用discussion about Global Actions作为棱镜,这是一个受Elm启发并允许您进行全局操作的库。

最佳答案

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

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

interface ComponentState {
   text: string
}


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

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

interface ResetAction {
    type: 'RESET_VALUE'
}


输入这两个动作的并集(请查看打字稿的区分并集):

type ComponentAction = SetAction | ResetAction;


减速器应具有以下签名:

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


现在要将“简单”组件“嵌入”到更大的组件中,我们需要将数据模型封装在父组件中:

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;


而这项技术最重要的是-母减速器:

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


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

关于redux - 如何组织可重用组件的Redux状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45368154/

相关文章:

testing - 从测试中重构 JUnit 规则

javascript - 无法从 redux 存储中获取数据

javascript - fetch 不应该在操作中 || reducer ?

angular - 如何使用路由器 socket 加载 Angular 组件

java - 多个组件的方法无效

c# - 如何在异常处理中使用接口(interface)

json - 如何安全地将 Redux 存储从服务器传递到客户端

json - Redux 和 Calendar 重复事件

java - 与 Java 进程之间的通信是否仍在微服务中?

c++ - 如何在没有重复代码的情况下处理 getter 的 const/non const 组合?