redux教程


原理

redux分3个部分:Store, Reducers, Action
Store:仓库,保存数据,组件从Store获取数据
Resucers: 模块,模块化管理数据,将数据传给Store
Action: 组件触发事件,创建一个Action对象,通过store.dispatch(action)将数据传给Resucers

添加浏览器Redux Dev Tools插件
创建配置文件
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
45
46
47
48
49
50
51
52
// src/store/index.js
import { createStore } from 'redux'
import reducer from './reducer' // 引入reducer模块
// const store = createStore(reducer) // 创建数据存储仓库
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() // 配置浏览器redux插件
)

export default store

// src/store/reducer.js
// redux数据管理模块
const defaultState = {} //储存数据
export default (state = defaultState, action) => {
console.log(state, action) // state: 原仓库状态,action: 新传递的值

// 第4步 触发事件,将新值赋值给Store,此时组件的数据并未更新
if (action.type === 'changeInput') { // 当action通过dispatch传值时,会触发这个方法,然后根据type进行判断
let newState = JSON.parse(JSON.stringify(state))
newState.inputValue = action.value
return newState
}

return state
}

// 后期文件管理:
+ store // 文件夹
+++ index.js

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux'
import * as page1 from './page1/reducer'
import * as page2 from './page2/reducer'
const store = createStore(
combineReducers({ ...page1, ...page2 })
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() // 配置浏览器redux插件
)

export default store

+++ page1 // 文件夹
+++++ action-type.js // 常亮存放type
+++++ action.js // 存放action
+++++ reducer.js

+++ page2 // 文件夹
+++++ action-type.js // 常亮存放type
+++++ action.js // 存放action
+++++ reducer.js
组件中使用store
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
// todoList.js
import store from './store'

class TodoList extends Component {
constructor (props) {
super(props)
// 第1步、获取store数据
this.state = store.getState()

// 第6步 Store数据更新会自动触发subscribe方法,所以会更新this.state
this.storeChange = this.storeChange.bind(this) //转变this指向
store.subscribe(this.storeChange) //订阅Redux的状态
}
render () {
return (
<div>
<input onChange={this.changeInputValue.bind(this)} />
</div>
)
}
changeInputValue () {
// 第2步、新建action对象
const action = {
type: 'changeInput',
value: e.target.value
}
// 第3步、将数据通过dispatch传给reducer
store.dispatch(action)
}

// 第5步 定义方法
storeChange(){
this.setState(store.getState()) // 重新获取数据
}
}
UI和业务逻辑分离
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// TodoList.js
import React, { Component } from 'react'
import TodoListUI from './ToduListUI'
import store from '../store'
class TodoList extends Component {
constructor (props) {
super(props)
this.state = store.getState()
this.storeChange = this.storeChange.bind(this) //转变this指向
store.subscribe(this.storeChange) //订阅Redux的状态
}
render() {
return (
<TodoListUI
list={ this.state.list }
deleteItem={ this.handleDelete.bind(this) }
addItem={ this.handleAdd.bind(this) }
changeInputValue={ this.changeInputValue.bind(this) }
/>
)
}
changeInputValue (e) {
const action = {
type: 'changeInput',
value: e.target.value
}
store.dispatch(action)
}
storeChange(){
this.setState(store.getState())
}
handleAdd () {
let data = [...this.state.list, this.state.inputValue]
const action = {
type: 'changeList',
value: data
}
store.dispatch(action)
}
handleDelete (index) {
let data = this.state.list
data.splice(index, 1)
const action = {
type: 'changeList',
value: data
}
store.dispatch(action)
}
}

export default TodoList



// TodoListUI.js
import React, { Component } from 'react'
import { Input, Button, List } from 'antd'

class TodoListUI extends Component {
render () {
return (
<div style={{margin:'10px'}}>
<List
bordered
dataSource={this.props.list}
renderItem={(item, index)=><List.Item>
<List.Item.Meta title={item}></List.Item.Meta>
<Button type="danger" onClick={this.props.deleteItem.bind(undefined, index)}>删除</Button>
</List.Item>}
/>
<div>
<Input
placeholder='Write something'
style={{ width:'250px', marginRight:'10px'}}
onChange={this.props.changeInputValue}
/>
<Button type="primary" onClick={this.props.addItem}>增加</Button>
</div>
</div>
)
}
}

export default TodoListUI
将UI组件变为无状态组件
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
// TodoList.js不需要改变
// TodoListUI.js

import React from 'react'
import { Input, Button, List } from 'antd'

const TodoListUI = (props) => {
return (
<div style={{margin:'10px'}}>
<List
bordered
dataSource={props.list}
renderItem={(item, index)=><List.Item>
<List.Item.Meta title={item}></List.Item.Meta>
<Button type="danger" onClick={props.deleteItem.bind(undefined, index)}>删除</Button>
</List.Item>}
/>
<div>
<Input
placeholder='Write something'
style={{ width:'250px', marginRight:'10px'}}
onChange={props.changeInputValue}
/>
<Button type="primary" onClick={props.addItem}>增加</Button>
</div>
</div>
)
}

export default TodoListUI