Redux - управление состоянием предварительной загрузки
Я создаю приложение, где мне нужно предварительно загрузить people
и planet
данные (вероятно, что в будущем могут быть добавлены дополнительные требования предварительной загрузки) при запуске приложения. Я хочу иметь значение в хранилище, которое представляет глобальное состояние приложения как loaded: <boolean>
. Значение будет истинным только тогда, когда требования предварительной загрузки people.loaded: true
и planet.loaded: true
верны. Магазин будет выглядеть примерно так:
Store
├── loaded: <Boolean>
├── people:
│ ├── loaded: <Boolean>
│ └── items: []
├── planets:
│ ├── loaded: <Boolean>
│ └── items: []
Отдельные создатели действия делают необходимые асинхронные запросы и действия отправки, которые обрабатываются редукторами people
и Planets
. Как показано ниже (использует 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 вызывает других создателей действий в site.js
непосредственно перед рендерингом в DOM, как показано ниже:
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. Что может быть масштабируемым способом проверки состояния приложения loaded
в нескольких компонентах React? Неправильно включать people
и planet
состояние для контейнеров, которые просто должны знать состояние глобального приложения и не обрабатывает рендеринг people
или Planets
. Также было бы больно управлять, когда глобальное состояние loaded
было бы необходимо в нескольких контейнерах.
Цитата из ответа Dan от Redux - несколько магазинов, почему бы и нет? вопрос.
Использование композиции редуктора позволяет легко реализовать "зависимые обновления" a la waitFor в Flux, написав редуктор, вручную вызывающий другие редукторы с дополнительной информацией и в определенном порядке.
4. Позволяет ли Дэн призывать другие редукторы вызывать вложенные редукторы?
Ответы
Ответ 1
Сначала позвольте мне исправить ваш пример.
Вместо
export function initApp () {
return (dispatch) => {
loadPeople()(dispatch);
loadPlanets()(dispatch);
};
}
вы можете (и должны) писать
export function initApp () {
return (dispatch) => {
dispatch(loadPeople());
dispatch(loadPlanets());
};
}
Вам не нужно передавать dispatch
в качестве промежуточного ПО аргумента.
Конечно, технически ваш код действителен, но я думаю, что мое предложение читается легче.
- Каковы наилучшие методы управления глобальным состоянием предварительной загрузки приложения в Redux?
То, что вы делаете, кажется правильным. Нет конкретных рекомендаций.
- Требуется наличие глобального загруженного состояния в хранилище?
Нет. Как говорит Дэвид в его ответе, вам лучше сохранить только необходимое состояние.
- Что может быть масштабируемым способом проверки состояния загруженного приложения в нескольких компонентах React? Не представляется правильным включать в список 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
};
}
- Помогает ли Дэн путем вызова других редукторов вызывать вложенные редукторы?
Да, состав редуктора обычно означает вызов вложенных редукторов.
Пожалуйста, обратитесь к моим бесплатным учебным видеороликам Egghead по этой теме:
Ответ 2
Загруженный флаг в вашем состоянии хранилища имеет смысл.
Однако у вас их слишком много. У вас есть state.people.loaded
, state.planets.loaded
, а также state.loaded
. Последнее происходит от первых двух. Ваш магазин действительно не должен содержать производное состояние. Либо есть только первые два или только последние.
Моя рекомендация состояла бы в том, чтобы сохранить первые два, т.е. state.people.loaded
и state.planets.loaded
. Тогда ваш подключенный компонент может получить конечное загруженное состояние. например.
function mapStateToProps(state) {
return {
loaded: state.people.loaded && state.planets.loaded,
people: state.people.items,
planets: state.planet.items
};
}