【问题标题】:Differentiate between stores in Redux在 Redux 中区分 store
【发布时间】:2019-01-27 16:12:27
【问题描述】:

我正在做一个项目,我希望数据分开存储(尽管在单个 redux 存储中)。假设我想区分数据,以下想法是否被视为反模式?

行动:

export const GET_DATA = 'GET_DATA';

export const getData = () => { 
  return async (dispatch) => {
    try {
      const data = await axios.get('/data');
      return onSuccess(data.data.response);
    } catch (err) {
      return onError(err);
    }

    function onSuccess(data) {
      dispatch({ type: 'GET_DATA', data });
    }
    function onError(error) {
      dispatch({ type: 'ERROR', error });
    }
  }
}

减速机:

import * as actionTypes from '../actionTypes';

const initialState = {
  data: [],
};

export default (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.GET_DATA:
      return {
        ...state,
        data: action.data
      }
    default:
      return state;  
  }
};

现在我想将data 分成data0data1(s. Action)。我考虑为第二个参数添加另一个属性,该属性被传递给减速器,例如转身:

function onSuccess(clients) {
  dispatch({ type: 'GET_DATA', data });
}

进入

function onSuccess(clients) {
  dispatch({ type: 'GET_DATA', data, classification: data0 });
}

这将允许我将 Reducer 重写为:

import * as actionTypes from '../actionTypes';

const initialState = {
  data0: [],
  data1: []
};

export default (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.GET_DATA:
      switch (action.classification) {
        case 'data0':
          return {
              ...state,
              data: action.data
          }
        case 'data1':
          return {
            // ...
          }
    }
    default:
      return state;  
  }
};

但是我不确定这是否被视为反模式?您能否分享您对此的想法或推荐另一种(更好的)解决方案?作为替代方案,我目前看到写了很多动作......例如GET_DATA_DATA0GET_DATA_DATA1...

谢谢!

【问题讨论】:

    标签: reactjs react-native redux store reducers


    【解决方案1】:

    我认为这是一种非常难以维护且不明确的方式来做任何事情。

    对于您拥有的每种不同类型的数据,您都需要创建一个新的 reducer。在我的个人项目中,我有一个 userconversationschat 减速器。

    有时,在您开始扩展之前,拥有小功能似乎很愚蠢和毫无意义,并且就像好的是什么改变了它以及我如何准确地跟踪发生了什么。

    我有一个用于填充初始 reducer 状态的 initialState.js 文件,这有助于让新开发人员更清楚数据在哪里。

    export default {
       chat: {
         id: null,
         messages: [],
       },
       conversations: [],
       user: {
          id: null,
          name: '',
       }
    }
    

    现在,每个 reducer 在调度操作时都非常清楚发生了什么以及正在更新哪些数据

    所以对于 chatReducer 它看起来像

    import * as actionTypes from '../actionTypes';
    
    import initialState from '../store/initialState.js'
    
    export default (state = initialState.chat, action) => {
      switch (action.type) {
        case actionTypes.RECEIVED_NEW_MESSAGE:
          return { ...state, messages: [...state.message, action.newMessage]}
        case actionTypes.FETCHED_CHAT_SUCCESS:
          return action.chat
        default:
          return state;  
      }
    };
    

    我要留给您的最后一件事是考虑测试以及更容易测试的内容以及测试如何让您对未来的重构充满信心。

    【讨论】:

    • 根据 initialState 的大小,您可以考虑将其拆分 - 每个 reducer 一个 initialState。无需导入 initialState 并使用 initialState.chat,您只需在聊天 reducer 中有一个 initialState 对象,在对话 reducer 中有另一个对象,等等。
    • @twils0 是对的。为多个减速器提供一个 initialState 文件感觉就像在自找麻烦。作为一般原则,将事物切分成尽可能小的部分,虽然一开始很乏味,但当应用程序扩展并且您尝试调试时确实会得到回报。
    • 一方面,如果状态的结构存在问题,如果您对所有的状态都使用相同的状态,那么您将导致许多不同的事物同时失败。另一方面,如果您有个人 initialState,则存在单点故障,因此更容易查明问题。
    • 我的意思是,这只是我的意见。做你觉得最好的事情。对于它的价值,据我回忆,我在 Redux 方面的经验远比我使用单独的 initialStates 的开发人员深入研究的所有演示。另外,我目前正在开发一个应用程序,其中不同的initialStates 都相当大并且与应用程序的其他部分无关,所以这可能也影响了我的直觉。
    • TallPaul, @223seneca 这都是关于模块化的。关于如何构建 redux 文件以实现良好扩展的文章不止几篇。在某些方面,它更像是一门艺术而不是一门科学。当你在谈论数百个reducer时,你不想搜索reducer文件,添加一些东西,然后搜索initialState文件,这可能是数千行代码,滚动浏览一段时间找到与你刚刚修改的reducer相关的部分,然后最后修改initialState状态的那部分。把相关的部分放到reducer里面比较容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-20
    • 2019-05-09
    • 2018-02-01
    • 2021-09-01
    • 1970-01-01
    • 2021-03-17
    相关资源
    最近更新 更多