redux-study

Posted by Zhang Tuanjie on 2019-07-21

redux的学习

项目源码TodoList

Redux介绍

Redux是一个用来管理管理数据状态和UI状态的JavaScript应用工具。随着JavaScript单页应用(SPA)开发日趋复杂,JavaScript需要管理比任何时候都要多的state(状态),Redux就是降低管理难度的。(Redux支持React,Angular、jQuery甚至纯JavaScript)

redux的图片

  • 从图中可以看出,如果不用Redux,我们要传递state是非常麻烦的。Redux中,可以把数据先放在数据仓库(store-公用状态存储空间)中,这里可以统一管理状态,然后哪个组件用到了,就去stroe中查找状态。如果途中的紫色组件想改变状态时,只需要改变store中的状态,然后其他组件就会跟着中的自动进行改变。

  • redux官方图片
    redux官方图片

    • 这张图,我在开始学的时候也没有看懂。不过,等学完redux这个状态管理工具,你就会理解这张图的含义了。

redux的使用

  1. 运行 npm i --save redux 安装redux

  2. 在项目的src目录下新建store文件夹,store中文件目录如下

1
2
3
4
5
6

├ store
├ actionCteater.js // 定义action的文件
├ actionTypes.js // 定义每一个action type
├ index.js // store的入口文件
└ reducer.js // store的管理模块

接下来,我会详细讲解,每一个文件的作用

  1. 在index.js中书写代码如下
1
2
3
4
5
6
7
import { createStore } from 'redux'; // 从redux中引入createStore方法

import reducer from './reducer.js' // 导入reducer文件

const store = createStore(reducer)

export default store // 导出store
  1. 在 reducer.js中书写一下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

const defaultState = {
inpVal : "say something",
list : [
"早上七点起床看redux的知识",
"早上八点洗漱吃饭",
"早上八点半继续学习",
]
}


// state: 指的是原始仓库里的状态。
// action: 指的是action新传递的状态。 (现在不理解没关系)
export default (state=defaultState, action)=>{
return state
}
  1. 在组件中使用redux的状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 第一步 导入store
import store from './store' // 书写正确的相对路径

// 第二步 在constructor中将store中状态的状赋值给state

constructor(props){
super(props)
this.state = store.getState() // 将store中状态的状赋值给state
store.subscribe(this.storeChange) // 订阅redux的状态,当redux中的state改变,将会触发 this.storeChange函数
}

// 第三不 将改变后的store 中 state重新赋值给state

storeChange=()=>{
this.setState(store.getState())
}

Redux Dev Tools的安装

我们已经制作了Redux中state仓库,也可以从仓库中取出数据了。接下来我们需要在控制台调试这些仓库里的数据,需要使用Redux DevTools。

  1. 安装 Redux DevTools 插件
    • 使用Chrome浏览器安装插件,在浏览器右上角有三个点,然后点击”更多工具”,再点击”扩展程序”,再点击右侧的”打开Chrome网上商店”,然后搜索Redux DevTools,可以看到Redux DevTools插件,直接安装就可以了。
  2. 配置Redux Dev Tools
    • 在 store 文件夹中的index.js中添加一行代码即可
1
2
3
4
5
6
7
8
9
10
11

import { createStore } from 'redux'; // 从redux中引入createStore方法

import reducer from './reducer.js' // 导入reducer文件

const store = createStore(reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()) // 核心代码

)

export default store // 导出store

通过action改变store中的state值

为了方便大家理解,我就不将 actionType 和 actionCreater 放在单独的文件夹中。后面代码优化的时候,我会分离代码

  1. 完整的TodoList.js组件代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

import React, { Component } from 'react';

import { Input, Button, List } from 'antd'
import store from './store/index.js'

class TodoList extends Component {
constructor(props) {
super(props)
this.state = store.getState()
store.subscribe(this.storeChange)
}
render() {
return (
<div style={{ margin: '10px' }}>
<div>
<Input ref="content" placeholder='write someting' style={{ width: '250px', marginRight: '10px' }} />
{/* 为按钮增加一个点击事件 */}
<Button type="primary" onClick={this.addItem}>增加</Button>
</div>
<div style={{ margin: '10px', width: '300px' }}>
<List
bordered
dataSource={this.state.list}
renderItem={(item, index) => (<List.Item onClick={this.delItem.bind(this, index)}>{item}</List.Item>)}
/>
</div>
</div>
);
}
storeChange = () => {
this.setState(store.getState())
}
addItem = () => {
let data = this.refs.content.state.value; // 通过refs获取到输入框中的值
let action = { // action 为一个对象,有两个属性
type: 'addItem' // 属性1 是action的type,判断reducer执行哪一个if语句
data // data 是要 改变的 值
}
store.dispatch(action) // 通过dispatch()方法传递给store
this.refs.content.state.value = "";
}
}
export default TodoList;
  1. reducer.js中的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

const defaultState = {
inpVal : "say something",
list : [
"早上七点起床看redux的知识",
"早上八点洗漱吃饭",
"早上八点半继续学习",
]
}


export default (state=defaultState, action)=>{
if(action.type === "addItem"){
let newState = JSON.parse(JSON.stringify(state)) // Reducer里只能接收state,不能改变state,所以我们要深 拷贝 state
newState.list.push(action.data) // 将新的todiitem push 到数组中
return newState;
}
return state
}