Redux - 管理预加载状态

Posted

技术标签:

【中文标题】Redux - 管理预加载状态【英文标题】:Redux - managing preload state 【发布时间】:2016-02-28 04:42:09 【问题描述】:

我正在构建一个应用程序,我需要在应用程序启动时预加载 peopleplanet 数据(将来可能会添加更多预加载要求)。我想在代表应用程序全局状态的商店中拥有价值loaded: <boolean>。只有当预加载要求people.loaded: trueplanet.loaded: true 为真时,该值才会为真。商店看起来像这样:

Store
├── loaded: <Boolean>
├── people:
│   ├── loaded: <Boolean>
│   └── items: []
├── planets:
│   ├── loaded: <Boolean>
│   └── items: []

单独的动作创建者发出所需的异步请求和调度动作,这些动作由 PeoplePlanets 减速器处理。如下图(使用redux-thunk):

actions/index.js

import * as types from '../constants/action-types';
import getPeople, getPlanets from '../util/swapi';

export function loadPeople () 
  return (dispatch) => 
    return getPeople()
      .then((people) => dispatch(addPeople(people)));
  ;


export function loadPlanets () 
  return (dispatch) => 
    return getPlanets()
      .then((planets) => dispatch(addPeople(planets)));
  ;


export function addPeople (people) 
  return type: types.ADD_PEOPLE, people;


export function addPlanets (planets) 
  return type: types.ADD_PLANETS, planets;


export function initApp () 
  return (dispatch) => 
    loadPeople()(dispatch);
    loadPlanets()(dispatch);
  ;

../util/swapi 处理从 LocalStorage 或发出请求获取人和行星数据。

initApp()action creator 在渲染到 DOM 之前调用 site.js 内的其他 action creator,如下所示:

site.js

import React from 'react';
import render from 'react-dom';
import Root from './containers/root';
import configureStore from './store/configure-store';
import initApp from './actions';

const store = configureStore();

// preload data
store.dispatch(initApp());

render(
  <Root store=store />,
  document.querySelector('#root')
);

1.在 Redux 中管理应用程序的全局预加载状态的最佳实践是什么?

2。是否有必要在商店中设置全局 loaded 状态?

3.在多个 React 组件中检查应用程序 loaded 状态的可扩展方式是什么? 对于只需要知道全局应用程序状态和不处理 PeoplePlanets 的渲染。当多个容器中需要全局 loaded 状态时,管理起来也很痛苦。


引用 Redux - multiple stores, why not? 问题中 Dan 的部分回答。

使用 reducer 组合可以很容易地在 Flux 中实现“依赖更新”,就像在 Flux 中的 waitFor 一样,方法是编写一个 reducer,手动调用其他 reducer 并以附加信息和特定顺序。

4. Dan 调用其他 reducer 是否意味着调用嵌套的 reducer?

【问题讨论】:

【参考方案1】:

首先,让我纠正你的例子。

代替

export function initApp () 
  return (dispatch) => 
    loadPeople()(dispatch);
    loadPlanets()(dispatch);
  ;

你可以(也应该)写作

export function initApp () 
  return (dispatch) => 
    dispatch(loadPeople());
    dispatch(loadPlanets());
  ;

您无需将 dispatch 作为参数传递 - thunk 中间件会处理此问题。 当然,从技术上讲,您的代码是有效的,但我认为我的建议更容易阅读。


    在 Redux 中管理应用程序的全局预加载状态的最佳做法是什么?

你所做的似乎是正确的。没有具体的最佳做法。

    是否需要在 store 中设置全局加载状态?

没有。正如 David 在 his answer 中指出的那样,您最好只存储必要的状态。

    在多个 React 组件中检查应用程序加载状态的可扩展方式是什么?对于只需要知道全局应用程序状态并且不处理 People 或 Planets 渲染的容器,包含 People 和 Planet 状态似乎是不正确的。此外,当多个容器中需要全局加载状态时,管理起来会很痛苦。

如果您担心重复,请创建一个“选择器”函数并将其放在减速器旁边:

// Reducer is the default export
export default combineReducers(
  planets,
  people
);

// Selectors are named exports
export function isAllLoaded(state) 
  return state.people.loaded && state.planets.loaded;

现在您可以从组件中导入选择器并在任何组件内的mapStateToProps 函数中使用它们:

import  isAllLoaded  from '../reducers';

function mapStateToProps(state) 
  return 
    loaded: isAllLoaded(state),
    people: state.people.items,
    planets: state.planet.items
  ;

    Dan 调用其他减速器是否意味着调用嵌套减速器?

是的,reducer 组合通常意味着调用嵌套的 reducer。 请参阅我关于此主题的免费 Egghead 教程视频:

Reducer Composition with Arrays Reducer Composition with Objects Reducer Composition with combineReducers() Implementing combineReducers() from Scratch

【讨论】:

感谢您的全面回答!【参考方案2】:

在您的商店状态中加载标志非常有意义。

但是你的数量太多了。你有state.people.loadedstate.planets.loadedstate.loaded。后者源自前两者。您的商店确实不应该包含派生状态。要么只有前两个,要么只有后者。

我的建议是保留前两个,即state.people.loadedstate.planets.loaded。然后您的连接组件可以导出最终加载状态。例如

function mapStateToProps(state) 
    return 
        loaded: state.people.loaded && state.planets.loaded,
        people: state.people.items,
        planets: state.planet.items
    ;

【讨论】:

但是如果在应用程序中多次使用state.people.loaded &amp;&amp; state.planets.loaded,维护它会不会很困难? Redux 示例通常显示这一点以减少可派生状态。但是我可以将加载的检查包装到一个接收状态并返回所需值的函数中。那将更具声明性。 您当然可能希望在应用程序中多次派生相同的东西。这是 Redux 没有提供解决方案的东西——它并不打算这样做。我仍然会保持商店状态极简主义。我最近采用的一种做法是将重复的功能导出到 utils/ 文件夹。 你对动作创建者在获取请求后将多个动作分派给loaderpeopleplanet减速器的想法有何看法?会出现问题,因为调度程序函数的顺序很重要,因为您不能声明 loader 减速器例如 people 在向 People 减速器调度操作之前已加载。 @RenārsVilnis 请查看 Redux repo 中的“购物车”示例。它展示了如何将这种“状态计算”封装到我们称之为“选择器”的函数中。将选择器与化简器放在一起——例如,isAllLoaded(state) 将计算出state.people.loaded &amp;&amp; state.planets.loaded,并且可以在整个应用程序中使用。

以上是关于Redux - 管理预加载状态的主要内容,如果未能解决你的问题,请参考以下文章

react+redux 中预加载组件数据的正确方法

如何预加载网络工作者资产

网络关闭的预加载功能

图像预加载技术(用作悬停状态 CSS 背景图像)似乎不适用于 Chrome

SpriteKit 内存管理预加载缓存和 fps 问题

实现图片预加载的几种方式