qbo*_*lec 13 code-reuse components separation-of-concerns redux
TL; DR:在具有管理其自己的状态有些复杂的逻辑可重用的组件的情况下(认为:与autocompleter Facebook的评论文字区域,表情符号等),一个人如何使用存储,操作和减速器进行管理的多个实例的状态这个组件遍布整个网站?
考虑官方redux回购中的真实示例.在其中我们有:
items
和方法renderItem
.特别是RepoPage
使用User
组件来显示为回购加星标的每个用户,并UserPage
使用Repo
组件来显示每个加星标的回购.假设我真的希望所有的状态都在Redux中.
特别是,我希望每个RepoPage和UserPage上的每个List的状态都由Redux管理.在这个例子中已经通过一个聪明的三级深树来处理:
store.pagination
)store.pagination.starredByUser
,store.pagination. stargazersByRepo
)store.pagination.starredByUser[login]
,store.pagination. stargazersByRepo[repo]
)我觉得这三个级别也对应于:组件类型,父类型,父ID.
但是,我不知道如何扩展这个想法,以处理List组件本身有很多子项的情况,其中一个状态值得在Redux中进行跟踪.
特别是,我想知道如何实现一个解决方案,其中:
User
组件保持完整Repo
组件有一个切换其背景颜色的按钮Repo
组件的状态由Redux管理(我很高兴使用Redux的一些扩展,它仍然使用Reducer,但是不想使用"只是将它保持在React本地状态",为此问题的目的)
我的研究到目前为止:
action.type
是由通过组件树告诉路径的子串.OTOH在这篇评论中,棱镜作者tomkis解释说,Redux缺少的Elm Architecture最重要的部分是动作的组合action.type
通过其安装路径识别组件实例,store
其中也对应于组件树中的路径,因为它的方式是由组件手动构建hWnd
为每个控件使用唯一的标识符,这使得检查是否action
适合你是非常容易的,并决定你的状态应该在哪里store
.我将尝试解释一个受 Elm lang 启发并已移植到 Typescript 的想法:
假设我们有一个非常简单的组件,其状态如下
interface ComponentState {
text: string
}
Run Code Online (Sandbox Code Playgroud)
可以通过以下 2 个操作减少组件。
interface SetAction {
type: 'SET_VALUE', payload: string
}
interface ResetAction {
type: 'RESET_VALUE'
}
Run Code Online (Sandbox Code Playgroud)
为这 2 个操作键入 union(请查看 Typescript 的 Discriminated Unions):
type ComponentAction = SetAction | ResetAction;
Run Code Online (Sandbox Code Playgroud)
用于此的减速器应具有以下签名:
function componentReducer(state: ComponentState, action: ComponentAction): ComponentState {
// code
}
Run Code Online (Sandbox Code Playgroud)
现在要将这个简单的组件“嵌入”到更大的组件中,我们需要在父组件中封装数据模型:
interface ParentComponentState {
instance1: ComponentState,
instance2: ComponentState,
}
Run Code Online (Sandbox Code Playgroud)
因为 redux 中的 action 类型需要全局唯一,我们不能为 Component 实例分派单个 action,因为它将由两个实例处理。其中一个想法是使用以下技术将单个组件的动作包装到父动作中:
interface Instance1ParentAction {
type: 'INSTNACE_1_PARENT',
payload: ComponentAction,
}
interface Instance2ParentAction {
type: 'INSTNACE_2_PARENT',
payload: ComponentAction,
}
Run Code Online (Sandbox Code Playgroud)
父操作联合将具有以下签名:
type ParentComponentAction = Instance1ParentAction | Instance2ParentAction;
Run Code Online (Sandbox Code Playgroud)
而这项技术最重要的事情 - 父级减速器:
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),
};
//
}
}
Run Code Online (Sandbox Code Playgroud)
使用 Discriminated Unions 还可以为 parent 和 child reducers 提供类型安全。