redux 时间旅行,你值得拥有!

栏目: 服务器 · 发布时间: 6年前

内容简介:顾名思义,就是可以随时穿越到以前和未来,让应用程序切换到任意时间的状态。我们都知道,一般应用状态都很复杂,创建、维护、修改和弄明白有哪些行为会影响状态都不是一件容易的事儿。整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。并使用纯函数计算下一个应用程序状态(不允许其他途径对 state 进行修改)。这些特征使 Redux 成为了一个可预测 的状态容器,这意味着如果给定一个特定应用程序状态和一个特定操作,那么应用程序的下一个

顾名思义,就是可以随时穿越到以前和未来,让应用程序切换到任意时间的状态。我们都知道,一般应用状态都很复杂,创建、维护、修改和弄明白有哪些行为会影响状态都不是一件容易的事儿。

redux 的解决方案

整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。并使用纯函数计算下一个应用程序状态(不允许其他途径对 state 进行修改)。这些特征使 Redux 成为了一个可预测 的状态容器,这意味着如果给定一个特定应用程序状态和一个特定操作,那么应用程序的下一个状态将始终完全相同。这种可预测性使得实现时间旅行变得很容易。redux 也相应的开发了一个带时间旅行的开发者工具 redux-devtools

redux 时间旅行,你值得拥有!

就是上面这个东西。下面就让我们跟随例子一起来了解下 redux 时间旅行的工作原理。

阅读要求

  • react 基础
  • redux 基础,明白 action,reducer,state 的关系。明白 combineReducer 的原理。

开始

项目地址:(github)[ github.com/wuyafeiJS/r… ]

预览:

redux 时间旅行,你值得拥有!
既然我们要实现时间旅行,那么第一步我们需要一个对象来记录每一次状态: 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 (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);
    }
  },
  ...
};
复制代码

配置 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>
      <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 有所帮助。


以上所述就是小编给大家介绍的《redux 时间旅行,你值得拥有!》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Code

Code

Charles Petzold / Microsoft Press / 2000-10-21 / USD 29.99

Paperback Edition What do flashlights, the British invasion, black cats, and seesaws have to do with computers? In CODE, they show us the ingenious ways we manipulate language and invent new means of ......一起来看看 《Code》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具