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

时间:2016-08-28 18:23:16

标签: design-patterns reactjs redux flux

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

示例包含帖子和用户的应用

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

给出帖子数组保留所有帖子init,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树的任何属性的所有选择器和组件!

  

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

所以我有这个想法可能是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 ??

这是正确的吗?我增加的复杂性超过了需要?

- >有人可以向我们展示已经运行的企业应用状态树的图片吗?所以我们可以从中学习如何组织国家?

2 个答案:

答案 0 :(得分:3)

  

重要的是要注意Redux商店实际上只有一个reducer功能。商店将当前状态和调度操作传递给那个reducer函数,并让reducer适当地处理事情。

     

显然,尝试在单个函数中处理每个可能的操作并不能很好地扩展,只是在函数大小和可读性方面,因此将实际工作拆分为可由顶层调用的单独函数是有意义的减速器。特别地,常见的建议模式是具有单独的子缩减器功能,其负责管理对特定键处的特定状态切片的更新。 Redux附带的combineReducers()是实现此目的的众多可能方法之一。我们还强烈建议您将商店状态保持平稳且尽可能正常化。但最终,您可以按照自己的方式负责组织减速器逻辑。

     

然而,即使您碰巧有许多不同的独立子减速器,甚至有深度嵌套状态,减速器速度也不太可能成为问题。 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

答案 1 :(得分:1)

  

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

这不确定,当商店的不相关属性发生变化时,组件不必重新呈现。如果你的组件是PureComponent,当属性的引用(原始道具的值)等于它们最后一次渲染时,它将不会被重新渲染。

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

reducer中返回的状态确实是一个新对象,但是你的posts数组在赋值后仍然是同一个数组(相等的引用)。因此,如果使用PureComponent,React会很好地处理它。

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