【发布时间】:2018-11-06 03:56:24
【问题描述】:
在 React-Redux 项目中,人们通常为每个连接的组件创建多个操作和缩减器。但是,这会为简单的数据更新创建大量代码。
为了简化和加快应用开发,使用单个通用动作和reducer来封装所有数据更改是否是一种好习惯。
使用这种方法会有什么缺点或性能损失。因为我认为没有明显的权衡,而且它使开发更加容易,我们可以将它们全部放在一个文件中!这种架构的示例:
// Say we're in user.js, User page
// state
var initialState = {};
// generic action --> we only need to write ONE DISPATCHER
function setState(obj){
Store.dispatch({ type: 'SET_USER', data: obj });
}
// generic reducer --> we only need to write ONE ACTION REDUCER
function userReducer = function(state = initialState, action){
switch (action.type) {
case 'SET_USER': return { ...state, ...action.data };
default: return state;
}
};
// define component
var User = React.createClass({
render: function(){
// Here's the magic...
// We can just call the generic setState() to update any data.
// No need to create separate dispatchers and reducers,
// thus greatly simplifying and fasten app development.
return [
<div onClick={() => setState({ someField: 1 })}/>,
<div onClick={() => setState({ someOtherField: 2, randomField: 3 })}/>,
<div onClick={() => setState({ orJustAnything: [1,2,3] })}/>
]
}
});
// register component for data update
function mapStateToProps(state){
return { ...state.user };
}
export default connect(mapStateToProps)(User);
编辑
所以典型的 Redux 架构建议创建:
- 包含所有操作的集中文件
- 包含所有减速器的集中文件
问题是,为什么是两步流程?这是另一个架构建议:
创建1 组文件,其中包含处理所有数据更改的所有setXField()。而其他组件只是使用它们来触发更改。简单。示例:
/** UserAPI.js
* Containing all methods for User.
* Other components can just call them.
*/
// state
var initialState = {};
// generic action
function setState(obj){
Store.dispatch({ type: 'SET_USER', data: obj });
}
// generic reducer
function userReducer = function(state = initialState, action){
switch (action.type) {
case 'SET_USER': return { ...state, ...action.data };
default: return state;
}
};
// API that we export
let UserAPI = {};
// set user name
UserAPI.setName = function(name){
$.post('/user/name', { name }, function({ ajaxSuccess }){
if (ajaxSuccess) setState({ name });
});
};
// set user picture URL
UserAPI.setPicture = function(url){
$.post('/user/picture', { url }, function({ ajaxSuccess }){
if (ajaxSuccess) setState({ url });
});
};
// logout, clear user
UserAPI.logout = function(){
$.post('/logout', {}, function(){
setState(initialState);
});
};
// Etc, you got the idea...
// Moreover, you can add a bunch of other User related methods,
// like some helper methods unrelated to Redux, or Ajax getters.
// Now you have everything related to User available in a single file!
// It becomes much easier to read through and understand.
// Finally, you can export a single UserAPI object, so other
// components only need to import it once.
export default UserAPI
请通读上面代码部分中的 cmets。
现在不再有一堆动作/调度程序/减速器。您有 1 个文件,其中包含用户概念所需的所有内容。 为什么这是一种不好的做法? IMO,它让程序员的生活轻松多了,其他程序员只需从上到下阅读文件即可了解业务逻辑,无需切换回来在 action/reducer 文件之间来回切换。哎呀,甚至不需要redux-thunk!您甚至可以一一测试功能。所以可测试性不会丢失。
【问题讨论】:
-
谈论性能但不回答您的问题,随着您的应用程序的增长,在返回之前检查状态的真实变化会很有趣,因为您正在使用扩展运算符更改对象引用,它总是会更改道具并重新调用渲染方法。我强烈推荐github.com/reduxjs/reselect,查看它的文档
-
如果这是您的问题,那么您可能根本不需要 redux。 redux 的目的是集中易于维护和可扩展的数据管理,虽然我相信你可以在这里找到很多东西 redux.js.org/recipes/reducing-boilerplate
-
@Lelouch 那么我使用什么库?能够使用与上述方法一样少的代码行来将状态更改应用于 DOM。
-
请看我问题的编辑部分,谢谢!
标签: javascript reactjs redux react-redux jsx