顾名思义,就是可以随时穿越到以前和未来,让应用程序切换到任意时间的状态。我们都知道,一般应用状态都很复杂,创建、维护、修改和弄明白有哪些行为会影响状态都不是一件容易的事儿。
整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。并使用纯函数计算下一个应用程序状态(不允许其他途径对 state 进行修改)。这些特征使 Redux 成为了一个可预测 的状态容器,这意味着如果给定一个特定应用程序状态和一个特定操作,那么应用程序的下一个状态将始终完全相同。这种可预测性使得实现时间旅行变得很容易。redux 也相应的开发了一个带时间旅行的开发者工具redux-devtools
- react 基础
- redux 基础,明白 action,reducer,state 的关系。明白 combineReducer 的原理。
预览:
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,重新分配,present 前面是 past,后面是 future。
那么我们如何去存放每一次变更的状态呢?我们需要找到一个入口,这个入口必须是每次触发状态变更都会经过的地方。而触发状态变更唯一的方式就是dispatch(action)
,想想,这样的地方好像只有一个地方,看过 redux 源码的同学肯定就是不陌生,那就是 combineReducer 生成的 reducers 纯函数。 combineReducer 负责整合多个 reducer,最终返回一个能够处理所有 action 的 reducers。让我们大致简单实现一下:
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 (pe) {case 'UNDO': // 后退stateHistory.undo();break;case 'REDO': // 前进do();break;case 'GOTO': // 定点指向State(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() { // 获取当前状态indexreturn this.past.length;},undo() { // 后退if (this.hasRecord('past')) {Index() - 1);}},redo() { // 前进if (this.hasRecord('futrue')) {Index() + 1);}},...
};
复制代码
配置 action:actions.js
...
export const redo = () => ({type: 'REDO'
});export const undo = () => ({type: 'UNDO'
});export const gotoState = stateIndex => ({type: 'GOTO',stateIndex
});
复制代码
准备工作都已经做完,接下来咱们直接在 react 组件内加上触发代码即可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><inputtype="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 有所帮助。
本文发布于:2024-02-04 18:48:02,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170714034358510.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |