redux的使用
单页应用越来越复杂,如react项目,状态复杂难以管理,redux可以很好地处理数据。
三个原则
单一数据源,应用的state存储在一个树上,这个树存储在唯一的store中
state只读,不是不能修改,唯一改变 state 的方法就是触发 action
使用纯函数来执行修改
构建一个最简单的redux案例
create-react-app脚手架创建一个react项目,删除多余代码,目录结构如下:

实现功能:两个按钮,加好按钮和减号按钮,每次点击数据变化1首先构建页面基本结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20export default () => {
const [n, setn] = useState(0);
const plus = () => {
};
const del = () => {
};
return (
<div>
<Button type="primary" onClick={plus}>
+
</Button>
<Button type="primary" onClick={del}>
-
</Button>
<div>{n}</div>
</div>
);
};写action,实际上就是对象,这里我们用函数的形式创建action,注意必须要有type属性
1
2
3
4
5
6
7
8
9
10
11
12export const addOne = (value) => {
return {
type: 'addOne',
value: value + 1
}
}
export const delOne = (value) => {
return {
type: 'delOne',
value: value - 1
}
}分别对应加和减操作,到时候把操作的数据传进来就好了。
reducer
action是会传给reducer进行处理的,reducer会接受两个参数,state和action,一般会给state附一个初始值1
2
3
4
5
6
7
8
9
10
11export default (state = 0, action) => {
console.log('ok', state);
switch (action.type) {
case 'addOne':
return state + 1
case 'delOne':
return state - 1
default:
return state
}
}要注意case后的名称不能写错,而且必须有返回值,也就是反会处理好之后的状态才行。
创建store
1
2
3
4
5const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store在Home组件中使用
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
31export default () => {
const [n, setn] = useState(0);
useEffect(() => {
//subscribe用于监听状态的变化
store.subscribe(() => {
//用getState方法获取reducer中return的值,每当加和减后都会获取最新的值
const newn = store.getState();
setn(newn);
});
});
const plus = () => {
//创建action,把当前状态传进去dispatch给reducer
const action = addOne(n);
store.dispatch(action);
};
const del = () => {
const action = delOne(n);
store.dispatch(action);
};
return (
<div>
<Button type="primary" onClick={plus}>
+
</Button>
<Button type="primary" onClick={del}>
-
</Button>
<div>{n}</div>
</div>
);
};这样最简单的redux就实现了,感觉还是有点复杂的,但是在项目越写越复杂的时候,就能体会到redux的好处了。
该案例git地址
react-redux
接下来使用react-redux实现一样的功能,页面结构调整一下。
react-redux有两个核心点—Provider和connect
- Provider用来包裹根组件App组件
- connect用来形成高阶组件,他有两个常用参数,mapStateToProps,mapDisPatchToProps,基本上就是一个接收state一个发送action,从名字也能大概了解,用connect方法形成的高阶组件,可以在被包裹组件内部用props获取,connect参数的返回值。
reducer
代码1
2
3
4
5
6
7
8
9
10export const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'add':
return { count: state.count + 1 }
case 'del':
return { count: state.count - 1 }
default:
return state
}
}A组件只有两个按钮,分别实现加和减
代码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
37import { connect } from 'react-redux'
function A(props) {
const handleAdd = () => {
//就是dispatch({type: 'add'})
props.addOne()
}
const handleDel = () => {
//就是dispatch({type: 'del'})
props.delOne()
}
return (
<>
<button onClick={handleAdd}>+</button>
<button onClick={handleDel}>-</button>
</>
)
}
const mapDispatchToProps = dispatch => {
//返回一个对象,在A组件中可以用props.addOne()/props.delOne()调用这两个函数,达到dispatch(action)的作用
return {
addOne: () => {
//相当于store.dispatch
dispatch({
type: 'add'
})
},
delOne: () => {
//相当于store.dispatch
dispatch({
type: 'del'
})
}
}
}
// 只发送,第一个参数填null即可,用connect对A组件加强
export default connect(null, mapDispatchToProps)(A)B组件只显示值
代码这样就用react-redux实现了同样的功能。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import { connect } from 'react-redux'
function B(props) {
return (
<div className="App">
{props.count}
</div>
);
}
const mapStateToProps = (state) => {
//接收reducer的返回对象,在B组件中用props.的方式使用数据
return state
}
//只接收返回的state,只需要第一个参数即可
export default connect(mapStateToProps)(B);
该案例git地址