Сколько времени на поездку?
Как следует из названия, вы можете передавать предыдущее и будущее в любое время, позволяя приложению переключаться в состояние в любое время. Все мы знаем, что общее состояние приложения очень сложное, создается, поддерживается, модифицируется, а сколько действий, которые повлияют на состояние, — дело непростое.
Это на вершине вещей. Давайте будем следовать примеру работы вместе, чтобы понять принципы Redux Time Travel.требования к чтению
- основы реакции
- Основа Redux, понимание взаимосвязи между действием, редьюсером и состоянием. Поймите принцип CombineReducer.
Начинать
Адрес проекта: (github)[GitHub.com/crowflyingjs/день…]
Предварительный просмотр:
Поскольку мы собираемся реализовать путешествие во времени, первым шагом, который нам нужен, является объект для записи каждого состояния:stateHistory.js
export default {
past: [],
futrue: [],
present: undefined,
gotoState(i) {
const index = i * 1;
const allState = [...this.past, this.present, ...this.futrue];
this.present = allState[index];
this.past = allState.slice(0, index);
this.futrue = allState.slice(index + 1, allState.length);
}
};
Мы делим состояния на три временных периода: прошлое, настоящее (есть только одно состояние) и будущее. Функция gotoState используется для путешествий во времени.Её реализация заключается в объединении всех состояний allState и их переназначении.Настоящему предшествует прошлое, а за ним следует будущее.
Итак, как мы сохраняем состояние каждого изменения? Нам нужно найти запись, и эта запись должна быть там, где срабатывает каждое изменение состояния. И единственный способ вызвать изменение состояния — этоdispatch(action)
, Подумайте об этом, похоже, есть только одно такое место, и студенты, которые видели исходный код редукса, должны быть знакомы с ним, это чистая функция редукторов, сгенерированных combReducer.
combReducer отвечает за объединение нескольких редюсеров и, наконец, возвращает редюсер, который может обрабатывать все действия. Давайте сделаем это примерно просто:
const combineReducer = obj => (state, action) => {
const finalState = {};
for (key in obj) {
finanlState[key] = obj[key](state[key], action);
}
return finalState; // 全局state
};
Далее воспользуемся идеей функционального программирования для улучшения функции Reducers, пусть запишет State:reducers.js
import stateHistory from './stateHistory';// 引入我们之前声明的history对象
// 原本我们是这样返回reducers的
export default combineReducers({
books: fetchReducer,
displayMode: bookDisplayReducer,
currentStatus: statusReducer,
topic: topicReducer
})
// 改造后如下:
export default history(
combineReducers({
books: fetchReducer,
displayMode: bookDisplayReducer,
currentStatus: statusReducer,
topic: topicReducer
})
);
// 我们用history包裹combineReducer,history实现如下
const history = reducers => (state, aciton) => {
switch (action.type) {
case 'UNDO': // 后退
stateHistory.undo();
break;
case 'REDO': // 前进
stateHistory.redo();
break;
case 'GOTO': // 定点指向
stateHistory.gotoState(action.stateIndex);
break;
default:
const newState = reducer(state, action);
stateHistory.push(newState);// 每次dipatch(action)都会像将状态保存到stateHistory
}
return stateHistory.present; // 返回当前状态
}
идеальноstateHistory.js
export default {
...
hasRecord(type) {// 查询是否有过去或者将来的状态
return this[type].length > 0;
},
hasPresent() { // 查询是否有现在的状态
return this.present !== undefined;
},
setPresent(state) {
this.present = state;
},
movePresentToPast() {
this.past.push(this.present);
},
push(currentState) { // 将状态都保存,并更新当前状态
if (this.hasPresent()) {
this.past.push(this.present);
}
this.setPresent(currentState);
},
getIndex() { // 获取当前状态index
return this.past.length;
},
undo() { // 后退
if (this.hasRecord('past')) {
this.gotoState(this.getIndex() - 1);
}
},
redo() { // 前进
if (this.hasRecord('futrue')) {
this.gotoState(this.getIndex() + 1);
}
},
...
};
Настройте действия:actions.js
...
export const redo = () => ({
type: 'REDO'
});
export const undo = () => ({
type: 'UNDO'
});
export const gotoState = stateIndex => ({
type: 'GOTO',
stateIndex
});
Подготовка завершена, и теперь мы можем напрямую добавить код триггера в компонент реакции.components/History.js
const History = ({ past, futrue, present, redo, undo, gotoState }) => {
const styles = {
container: {
marginLeft: '20px',
cursor: 'pointer'
},
link: { textDecoration: 'none' },
input: { cursor: 'pointer' }
};
const RightArrow = () => (
// 前进
<a href="#" style={styles.link} onClick={() => redo()}>
→
</a>
);
const LeftArrow = () => (
// 后退
<a href="#" style={styles.link} onClick={() => undo()}>
←
</a>
);
const max = () =>
(past ? past.length : 0) +
(present ? 1 : 0) +
(futrue ? futrue.length : 0) -
1;
const value = () => (past ? past.length : 0);
return (
<span>
<input
type="range"
min={0}
max={max()}
value={value()}
onChange={e => {
gotoState(e.target.value);
}}
style={styles.input}
/>
{past && past.length > 0 ? <LeftArrow /> : null}
{futrue && futrue.length > 0 ? <RightArrow /> : null}
</span>
);
};
над! Я надеюсь, что это поможет вам понять Redux.