Reactjs Redux 我们应该为状态树中的每个对象创建 sub reducer 吗?

Posted

技术标签:

【中文标题】Reactjs Redux 我们应该为状态树中的每个对象创建 sub reducer 吗?【英文标题】:Reactjs Redux should we create sub reducer for every object in the state tree? 【发布时间】:2017-01-04 18:53:41 【问题描述】:

据我所知,redux 应用程序维护状态树的正确方法是对其进行规范化,尽可能扁平化数据并使用 combinereducer 创建状态树的切片。

具有帖子和用户的示例应用

const rootReducer = combineReducers(
  user:userReducer,
  posts:postsReducer,
);
const store = createStore(rootReducer);

给定帖子数组保持所有帖子初始化,State.posts 看起来像

let initialState =   
    byId:1:id:1,title:'post1',
    ids:[1],
    meta_data:unread:1,old:0
    

现在,如果我们有大约 10,000 个帖子,我们最终会得到 state.post.ids.length === 10000,这很好,

问题是。因为我们的 reducer 每次需要更新时都会返回一个新状态,例如我们需要更新 meta_data.unread 为等于 0,我们将返回一个新的 Post 对象。

return object.assign(,state,meta_data:unread:0,old:1)

这将重新渲染所有使用state.post树属性的选择器和组件!

这听起来像个问题对吗?** 我们想要的只是更新未读计数器.. 为什么要重新计算 Posts 的所有选择器和组件?

所以我有这个想法,可能是 state.posts 也应该使用 combineReducers 组成,以便每个 attr.的帖子应该有一个自己的减速器。

将postsReducer拆分成多个

postsMainReducer, ==> deal with adding or removing posts
postMeta_dataReducer, ==> deal with meta_data of posts
singlePostReducer ==> Now this is dynamic !! how can i create such ??

这是正确的吗?我增加了比需要更多的复杂性?

-->谁能给我们看一张已经在运行的企业应用状态树的图片?所以我们可以从中学习如何组织状态?

【问题讨论】:

【参考方案1】:

需要注意的是,一个 Redux 存储实际上只有一个 reducer 函数。存储将当前状态和分派的操作传递给该减速器函数,并让减速器适当地处理事情。

显然,试图在单个函数中处理所有可能的操作并不能很好地扩展,仅就函数大小和可读性而言,因此将实际工作拆分为可由顶层调用的单独函数是有意义的减速器。特别是,常见的建议模式是拥有一个单独的 sub-reducer 函数,负责管理对特定键的特定状态片的更新。 Redux 附带的 combineReducers() 是实现这一目标的众多可能方法之一。还强烈建议让您的商店状态尽可能平坦和规范化。但最终,您将负责以任何您想要的方式组织您的 reducer 逻辑。

然而,即使你碰巧有许多不同的独立子减速器,甚至有深度嵌套的状态,减速器的速度也不太可能成为问题。 javascript 引擎每秒能够运行大量的函数调用,并且您的大多数子缩减程序可能只是使用 switch 语句并默认返回现有状态以响应大多数操作。

如果你真的关心 reducer 的性能,你可以使用 redux-ignore(https://github.com/omnidan/redux-ignore) 或 reduxr-scoped-reducer(https://github.com/chrisdavies/reduxr-scoped-reducer) 等实用程序来确保只有特定的 reducer 监听特定的操作。你也可以使用 redux-log-slow-reducers(https://github.com/michaelcontento/redux-log-slow-reducers) 做一些性能基准测试。

这是我最常参考的项目-

这些是 Redux 的实际用途。

这里有一些链接:

https://github.com/andrewngu/sound-redux

https://github.com/echenley/react-news

https://github.com/paulhoughton/remember/

https://github.com/paulhoughton/mortgage/

https://github.com/benoitvallon/react-native-nw-react-calculator

https://github.com/jfurrow/flood

https://github.com/FH-Potsdam/shifted-maps

https://github.com/quirinpa/2post

https://github.com/karlguillotte/Ctfs

https://github.com/madou/gw2armory.com

【讨论】:

只是添加到这个;真正的答案是“不要过早优化”。 React 和 Redux 旨在即使在大量数据下也能非常快速地运行。让他们做他们的工作。等到您发现问题后再尝试解决(如果您想尽早看到问题,请进行基准测试)。【参考方案2】:

这将重新渲染所有使用任何选择器和组件 state.post 树的属性!

这并不确定,当商店的无关属性发生变化时,组件不必重新渲染。如果您的组件是PureComponent,则当属性的引用(原始道具的值)等于它们上次渲染的值时,它将不会重新渲染。

var foo =  a: [1, 2, 3], someCount: 1 ;
var bar = Object.assign(, foo,  someCount: 2 );
console.log(foo.a === bar.a);
// true

reducer 中返回的状态确实是一个新对象,但你的帖子数组在分配之后仍然是同一个数组(相等引用)。所以如果你使用 PureComponent,React 可以很好地处理这个问题。

接下来您可能会偶然发现:如果您在选择器中使用从商店或多个商店派生的派生数据,则可以使用reselect 到memoize 结果,这样引用保持不变 - 无需重复需要渲染。 An article describes the problem with creating new arrays for derived or empty data in each render cycle.

【讨论】:

以上是关于Reactjs Redux 我们应该为状态树中的每个对象创建 sub reducer 吗?的主要内容,如果未能解决你的问题,请参考以下文章

获取组件(窗口小部件)中相应的redux存储状态更新的数据

ReactJS Redux State(全局状态)+ React.Context(本地状态)

reactjs:动作后redux不会重新渲染

Redux学习笔记

Reactjs 列表优化的一些心得

GraphQL 如何取代 Redux