Redux - 管理预加载状态

Redux - managing preload state

我正在构建一个应用程序,我需要在其中预加载 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() 动作创建者在渲染到 DOM 之前调用 site.js 中的其他动作创建者,如下所示:

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 状态的可扩展方式是什么? 为只需要的容器包含 PeoplePlanet 状态似乎不正确了解全局应用程序状态并且不处理 PeoplePlanets 的呈现。当多个容器中需要全局 loaded 状态时,管理起来也会很痛苦。


引用 Dan 在 问题中的部分回答。

Using reducer composition makes it easy to implement "dependent updates" a la waitFor in Flux by writing a reducer manually calling other reducers with additional information and in a specific order.

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

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

但是你的数量太多了。您有 state.people.loadedstate.planets.loaded 以及 state.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
    };
}

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

而不是

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

你可以(也应该)写

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

你不需要传递 dispatch 作为参数——thunk 中间件会处理这个。
当然,从技术上讲,您的代码是有效的,但我认为我的建议更容易理解。


  1. What are the best practices for managing global preload state of the application in Redux?

你所做的似乎是正确的。没有特定的最佳实践。

  1. Is having a global loaded state in the store necessary?

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

  1. What would be a scalable way of checking app loaded state in multiple React components? It doesn't seem right to include People and Planet state for containers that just needs to know the global app state and doesn't handle rendering of People or Planets. Also that would be painful to manage when the global loaded state would be needed in multiple containers.

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

// 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
  };
}
  1. Does Dan by calling other reducers mean calling nested reducers?

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