[英]The proper place to change state in react redux
正如文檔所說:
在減速器中永遠不應該做的事情:
- 改變其論點;
- 執行副作用,例如API調用和路由轉換;
- 調用非純函數,例如Date.now()或Math.random()。
如果我遵循該原則,那么關於代碼組織(我的應用程序是文件管理器)會存在一些問題。
例如,
默認的減速器是這樣的:
export default function (state = initialState, action) {
const { path } = action
if (typeof path === 'undefined') {
return state
}
const ret = {
...state,
[path]: parentNode(state[path], action)
};
switch (action.type) {
case OPEN_NODE:
case GO_PATH:
ret['currentPath'] = path
break
default:
break
}
return ret
}
state[path]
數據結構喜歡:
{
'open': false,
'path': '/tmp/some_folder',
'childNodes' : [ {'path':'/some/path', 'mode': '0755', 'isfolder': true}, ....],
'updateTime': Date.now()
}
現在我需要幾個動作,例如ADD_CHILD
, DELETE_CHILD
, RENAME_CHILD
, MOVE_CHILD
,有兩個提示(通過動作或reducer中的更改狀態):
動作:
export function updateChildNodes(path, nodes) {
return {
type: UPDATE_CHILD_NODES,
path: path,
loading: false,
loaded: true,
childNodes: nodes,
};
}
export function addChild(path, node) {
return (dispatch, getState) => {
const state = getState().tree[path]
var childNodes = state.childNodes ? state.childNodes :[]
childNodes.push(node)
return dispatch(updateChildNodes(path, childNodes))
}
}
export function deleteChild(parent_path, child_node) {
return (dispatch, getState) => {
const state = getState().tree[parent_path]
var childNodes = state && state.childNodes ? state.childNodes : []
for (var i=0; i <=childNodes.length; i++){
if (childNodes[i].path == child_node.path){
childNodes.splice(i, 1)
return dispatch(updateChildNodes(parent_path, childNodes))
}
}
}
}
export function deleteNode(node) {
return (dispatch, getState) => {
// ajax call
return api.deleteChild(node.path, () => {
dispatch(deleteChild(node.parent, node))
})
}
}
.....
parentNode減速器:
function parentNode(state, action) {
switch (action.type) {
case UPDATE_CHILD_NODES:
return {
...state,
childNodes: action.childNodes
}
default:
return state;
}
}
所有變量都從動作傳入parentNode,parentNode只是將更改分配給狀態不會做任何其他事情。
remove node
和add node
所有邏輯均由操作完成,只有parentNode
UPDATE_CHILD_NODES
。
動作:
export function updateChildNodes(path, nodes) {
return {
type: UPDATE_CHILD_NODES,
path: path,
loading: false,
loaded: true,
childNodes: nodes,
};
}
export function addChild(path, node) {
return {
type: ADD_CHILD,
path: path,
node: node,
};
}
export function deleteChild(path, node) {
return {
type: DELETE_CHILD,
path: path,
node: node,
};
}
export function deleteNode(node) {
return (dispatch, getState) => {
// ajax call
return api.deleteChild(node.path, () => {
dispatch(deleteChild(node.parent, node))
})
}
}
.....
parentNode減速器:
function parentNode(state, action) {
switch (action.type) {
case DELETE_CHILD:
let childNodes = state.childNodes.slice() // have to clone obj
for (var i=0; i <=childNodes.length; i++){
if (childNodes[i].path == action.node.path){
childNodes.splice(i, 1)
}
}
return {
...state,
childNodes: childNodes
};
case ADD_CHILD:
let childNodes = state.childNodes.slice() // have to clone obj
childNodes.push(node)
return {
...state,
childNodes: childNodes
};
case UPDATE_CHILD_NODES:
return {
...state,
childNodes: action.childNodes
}
default:
return state;
}
}
在我的選擇中,解決方案2更具可讀性和美觀性。 但是通過突變克隆的obj來更改狀態是否很好? 當我需要通過Date.now()
設置updateTime
時,我必須從操作生成它並傳遞給reducer,以便在不同的位置生成狀態變量(但我想將它們放在一起...)
有什么意見嗎?
從這個終極版的討論在這里 :
最佳做法是將大多數邏輯放在動作創建者中,並使簡化器盡可能簡單(更接近於選項1),原因如下:
業務邏輯屬於行動創造者。 減速器應該愚蠢而簡單。 在許多情況下,這並不重要,但是一致性很好,因此最好始終如一。 原因有兩個:
通過使用像redux-thunk這樣的中間件,動作創建者可以是異步的。 由於您的應用程序通常需要對商店進行異步更新,因此某些“業務邏輯”將最終出現在您的操作中。
動作創建者(更准確地說是他們返回的重擊)可以使用共享選擇器,因為它們可以訪問完整狀態。 減速器不能,因為它們只能訪問其節點。
使用redux-thunk,單個動作創建者可以調度多個動作-這使復雜的狀態更新更加簡單,並鼓勵更好的代碼重用。
對於小型應用程序,我通常將邏輯付諸於行動創建者。 對於更復雜的情況,您可能需要考慮其他選擇。 以下是有關不同方法的優缺點的摘要: https : //medium.com/@jeffbski/where-do-i-put-my-business-logic-in-a-react-redux-application-9253ef91ce1#。 k8zh31ng5
另外,看看Redux中間件。
中間件提供了在調度動作與其到達化簡器之間的第三方擴展點。
這是Redux的作者Dan Abramov提供的答案: 為什么我們需要中間件來實現Redux中的異步流?
這是Redux官方文檔: http : //redux.js.org/docs/advanced/Middleware.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.