Redux 的简单实现

什么是 Redux

Redux 是 JavaScript 的状态容器,提供可预测化的管理,可以让你构建一致化的应用,运行与不同的环境(客户端、服务器、原生应用),并且易于测试。(个人理解:Redux 和 Vuex 很像

优点:

  • 可预测:始终有一个唯一的准确的数据源(single source of truth)就是 store,通过 actions 和 reduces 来保证整个应用状态同步,做到绝不混乱
  • 易维护:具备可预测的结果和严格的组织结构让代码更容易维护
  • 易测试:编写可测试代码的首要准则是编写可以仅做一件事并且独立的小函数(single responsibility),Redux的代码几乎全部都是这样的函数:短小·纯粹·分离

什么时候使用 Redux

  • 某个组件的状态,需要共享
  • 某个数据需要在任何地方都可以拿到
  • 一个组件需要改变全局状态
  • 一个组件需要改变另一个组件的状态

也就是:在 多交互、多数据源 中可以考虑使用 redux。

Redux 的三个基本原则

  • 单一数据源:整个应用的 state 被储存在一棵 Object tree 中,并且这个 Object tree 只存在于唯一一个 store
  • reducer:形式为(state,action)=> state 的纯函数,功能是提供action 来修改 state
  • store:用于存储 state,你可以把它看成一个容器,整个应用只能有一个 store

简单来理解就是:在组件中共享的数据都存储在 store 中,而 store 是只读的,我们只可以通过 reducer 来改变 store 中的数据

说太多的理论也没多大用,先看一个简单的 demo 吧

在这里插入图片描述

大概就这样,没写样式。

主要的功能就是当我点击增加的话,就将文本框中值添加到下面的 ol 中,当我们点击 ol 中的一项时,会删除你点击的那一项

你肯认为很简单,O(∩_∩)O哈哈~,这次我们使用redux,所有数据到会放到state 中的 store 中,这就简单了。

好了,看下面的解析。

Redux 工作流程

在这里插入图片描述

如何改变数据呢?

看上图所示:

  1. 首先我们会通过 ActionCreators 触发给 Store ,而 Store 默默的把这个触发交给了 Reducers
  2. Reducers 处理完结果后会将结果返回给 Store ,从而改变 Store ,这个时候我们必须使用 Store 的一个方法将我们改变的数据渲染到我要改变的组件上

安装

先安装 redux

npm install --save redux

使用

刚刚开始学习 redux,感觉比较怪异,好在多写几遍就好多了。

我使用了 create-react-app 帮我创建一个 react 项目(不用配置),如果没安装,使用进行安装:

npm i create-react-app -g

目录结构:

在这里插入图片描述

其中src/store下文件都是一些使用 redux 的文件,src/App.js 这个文件中主要在这里写UI的

App.js 的代码:

import React,{Component} from 'react';

import store from './store/store';

import {
  addItem,
  alertInputValue,
  deleteItem
} from './store/actionCreator';

console.log(store);

class App extends Component{
  constructor(props) {
    super(props);
    // 使用 store.getState() 来获取仓库中的数据
    this.state = store.getState();
  }
  render() {
    let {state} = this;
    let {inputValue,list} = state;
    // store.subscribe监听 store 中数据改变,从而我们可以重新渲染数据
    // 只要 store 中的数据发生改变,这个函数就会被触发
    store.subscribe(()=> {
      const {inputValue,list} = store.getState();;
      this.setState({
        inputValue: inputValue,
        list : list,
      })
    });
    return (
      <div className="App" style={{margin: '20px'}} >
        <div>
          <div>
            <input 
              placeholder='请输入数据' 
              style={{width: '300px'}} 
              value={inputValue} 
              onChange={(e) => {
                store.dispatch(alertInputValue(e.target.value))
              }}
            />
            <button 
              type="primary" 
              style={{marginLeft:'36px'}}
              onClick={() => {
                store.dispatch(addItem(inputValue))
              }}
            >
              {/* 当我们点击增加按钮的时候会 使用 store.dispatch 来触发 reducer,而他会将 addItem(inputValue)返回的参数,传递给 action */}
              {/* 而我们通过 reducer 中的 action 来判断到底怎么处理函数 */}
                增加
            </button>
          </div>
          <ol>
            {list.map((item,index) => {
              return (
                <li key={index}                 
                  onClick={() => {
                    console.log(index);
                    store.dispatch(deleteItem(index))
                  }}
                >
                  {item}
                </li>
              )
            })}
          </ol>
        </div>
      </div>
    );  
  }

}

export default App;

以下都是 store 文件夹下的代码

store.js 的代码:

/**
 * 该文件主要是创建一个 store 对象,并将它默认导出
 * 其中:createStore 的参数:
 *      第一个:reducer 就是我们流程图中的 Reducers
 *      第二个:是 Chrome 下的一个查看、调试 redux 的工具
 */
import {createStore} from 'redux';
import reducer from './reducer';

export default createStore(
    reducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

那个工具在哪下载呢?

先声明:要知道怎么科学上网

这个 “应用” 在左上角

在这里插入图片描述

进入到这个页面

在这里插入图片描述

下载这个就行了

在这里插入图片描述

使用:

在这里插入图片描述
在这里插入图片描述

就看到我们的数据了

reducer.js 的代码 :

/**
 * 该文件导出一个函数:
 *      函数的参数:
 *          state: 表示 store 中的存储的数据(状态)
 *          action: 通过 action 来改变 state 的数据
 */

import {
    ADD_ITEM,
    DELETE_ITEM,
    ALERT_INPUTVALUE
} from './actionTypes';

let defaultState = {
    inputValue : '请输入东西',
    list: [
        'Racing car sprays burning fuel into crowd.',
        'Japanese princess to wed commoner.',
        'Australian walks 100km after outback crash.',
        'Man charged over missing wedding girl.',
        'Los Angeles battles huge wildfires.',
    ]
}

export default (state = defaultState,action) => {
    let newState = JSON.parse(JSON.stringify(state));
    switch (action.type) {
        case ADD_ITEM:
            newState.list.push(newState.inputValue);
            newState.inputValue = '';
            return newState;
        case DELETE_ITEM:
            newState.list.splice(action.index,1);
            return newState;
        case ALERT_INPUTVALUE:
            newState.inputValue = action.text;
            return newState;
    }
    return state;
}

actionTypes.js 的代码:

/**
 * 该文件导出都是一些常量:就是 actionCreators.js 文件要使用的常量
 * 	    其实;直接在 actionCreators 中写这些 字符串也行,
 *      但是:当我们做一个大型的项目的时候,这样做可以迅速的排错,养成好习惯,增加代码的可维护性
 */
export const ADD_ITEM = 'ADD_ITEM';

export const DELETE_ITEM = 'DELETE_ITEM';

export const ALERT_INPUTVALUE = 'ALERT_INPUTVALUE';

actionCreator.js 的代码:

/**
 * 导出的是一些对象:
 *      例如:
 *          {
 *              type: ADD_ITEM,
 *              text: text,
 *          }
 *   其中: type 主要是来区别,我们应该使用哪一种 reducer,配合 store.dispatch 函数来使用
 */
import {
    ADD_ITEM,
    ALERT_INPUTVALUE,
    DELETE_ITEM
} from './actionTypes';

export const addItem = function(text) {
    return {
        type: ADD_ITEM,
        text,
    }
}

export const alertInputValue = function(text) {
    return {
        type: ALERT_INPUTVALUE,
        text,
    }
}

export const deleteItem = function(index) {
    return {
        type: DELETE_ITEM,
        index,
    }
}

大概就这样把:感觉我也不是特别懂,主要是我也没写多少遍,这个还是要多多练习才行,刚刚开始的时候,你肯定会感觉比较绕的,多敲几遍,多想几遍会好多的

这个仅仅只是 redux 最简单的用法,还有什么中间件,合并之类的。

参考资料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章