Redux - 为啥在根目录下加载所有状态

Posted

技术标签:

【中文标题】Redux - 为啥在根目录下加载所有状态【英文标题】:Redux - why loading everything in state at rootRedux - 为什么在根目录下加载所有状态 【发布时间】:2016-03-12 05:16:48 【问题描述】:

我正在尝试理解 Redux,但遇到了一些困难。

我理解 combineReducer 的概念,即....

var reducer = combineReducers(
    user: userReducer,
    products: productsReducer
)

但是,如果我有数千种产品,只能在产品页面上找到。我不明白为什么我需要在根目录下加载它们;对我来说,这将减慢应用程序的初始启动速度,因为除非用户转到产品页面,否则不需要这些东西。

这只是 redux 的方式吗?

【问题讨论】:

【参考方案1】:

在 Redux 应用程序中,您总是在开始时构建整个状态。使用 Redux,你有一个 store 和一个 state——一切都应该从一个 state 向下渗透到组件上的 props。但是,这并不意味着您实际上需要在启动时将所有 数据 加载到状态中,只是 结构 需要在那里。这就是为什么你应该为每个 reducer 设置一个初始状态对象。

假设您从数据库加载了数千条产品记录。在您的产品减速器中,您可以执行以下操作:

const initialState = 
    data: []
;

//use ES6 default parameters
function productsReducer (state = initialState, action) 
    switch (action.type) 
    case 'GET_PRODUCTS':
        //return data from action
        return 
            data: action.result
        ;
    default: 
        return state;
    

这意味着当你启动你的应用程序时,如果你使用你在帖子中声明的完整 reducer,你的应用程序状态将如下所示:


    user: ,
    products: 
        data: []
    

products.data 将是一个空数组,直到您触发实际需要您加载产品数据的操作(即您转到应用程序中的产品页面或其他内容)。确实,如果您随后转到应用程序中的其他位置,产品数据将保留在您的状态中,但这是一件好事 - 下次您呈现产品页面时,您将已经拥有可供您使用的数据,而无需创建数据库查找。

【讨论】:

谢谢老兄,我还没有看到它解释得像你刚才那样。你现在展示的对我来说很有意义。我希望有更多关于远程数据的真实世界示例和更少的待办事项:(。但是谢谢! 我应该指出,我在 reducer 中稍微编辑了我的评论,因为从技术上讲,您不应该在 reducer 中进行 ajax 调用(尽管它通常会起作用)。更好的流程是在您的操作中创建您的 ajax 调用(承诺),然后有一些中间件为您运行它并将其发送到减速器。我发现本教程非常有帮助。特别是查看 src 并查看 promise-middleware 以及它是如何实现的github.com/happypoulp/redux-tutorial @SarasotaSun:你看过redux repo 中的“真实世界的例子”吗? github.com/rackt/redux/tree/master/examples/real-world【参考方案2】:

在我们的应用中,我们为产品制作了一个 API,每页限制为 15 个。所以我们的 reducer 是这样的。

collection: 
  "total": 0,
  "per_page": 0,
  "current_page": 0,
  "last_page": 0,
  "from": 0,
  "to": 0,
  data: []
,

isFetching: false,
isFetchingError: false

在第一次加载时,我们获取了有限数量的产品,然后我们对其进行了分页.. 在 redux 中使用选择器https://github.com/rackt/reselect

加载成千上万的数据会使您的应用变得非常缓慢。

const paginated = (state = initialState, action) => 
 switch (action.type) 
case FETCH_PAGINATED_PRODUCTS:
  return 
    ...state,
    isFetching: true,
    isFetchingError: false
  ;

case FETCH_PAGINATED_PRODUCTS_SUCCESS:
  return 
    ...state,
    collection: action.payload,
    isFetching: false
  ;

case FETCH_PAGINATED_PRODUCTS_ERROR:
  return 
    ...state,
    isFetching: false,
    isFetchingError: true
  ;

default:
 return state

我们使用axios 请求: https://github.com/mzabriskie/axios

【讨论】:

你有一个 github 仓库吗? 它是一个私人仓库,我们在公司使用它。机密事项。只是在这里给你一些想法:) 看看这个异步示例 redux github.com/rackt/redux/tree/master/examples/real-world 我明白了。有一个关于你如何使用 redux 在 axios 上处理异步的示例?【参考方案3】:

下面是我们如何在 redux-async 中实现 axios

 export function getAll(page = 1) 
  return (dispatch, getState) => 
    const state = getState();
    const  filters  = state.products.paginated;

    if ( state.products.paginated.isFetching ) 
      return;
    

    dispatch( type: FETCH_PAGINATED_PRODUCTS );

    return axios
      .get(`products?page=$page&limit=16&filters=$JSON.stringify(filters)`)
      .then((res) => dispatch(
        type: FETCH_PAGINATED_PRODUCTS_SUCCESS,
        payload: res.data
      ))
      .catch((res) => dispatch(
        type: FETCH_PAGINATED_PRODUCTS_ERROR,
        /*payload: res.data.error,*/
        error: true
      ));
  


export function get(id) 
  return (dispatch, getState) => 
    const state = getState();

    if ( state.products.resource.isFetching ) 
      return;
    

    dispatch( type: FETCH_PRODUCT );

    return axios
      .get(`products/$id`)
      .then((res) => dispatch(
        type: FETCH_PRODUCT_SUCCESS,
        payload: res.data.data
      ))
      .catch((res) => dispatch(
        type: FETCH_PRODUCT_ERROR,
        /*payload: new Error(res.data.error),*/
        error: true
      ));
  

【讨论】:

以上是关于Redux - 为啥在根目录下加载所有状态的主要内容,如果未能解决你的问题,请参考以下文章

请求完成后触发 Redux 异步操作。为啥?

Redux 状态在窗口重新加载时重置(客户端)

我的 Redux 状态发生了变化,为啥 React 没有触发重新渲染?

为啥这个 Redux Saga Selector 不工作?我似乎无法访问状态

React Redux:为啥这个嵌套组件没有从 redux 状态接收道具?

为啥初始状态没有保留在 react-redux 中