簡體   English   中英

在React Redux中更改狀態的正確位置

[英]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_CHILDDELETE_CHILDRENAME_CHILDMOVE_CHILD ,有兩個提示(通過動作或reducer中的更改狀態):

1.操作中的所有功能代碼:

動作:

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 nodeadd node所有邏輯均由操作完成,只有parentNode UPDATE_CHILD_NODES

2.動作只是將數據發送到減速器,讓減速器處理

動作:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM