Redux在维基百科中给出的定义是应用程序状态管理的JavaScript函数库,也被称为可预测的状态管理机,我在最初看到这个解释的时候并不能很好的理解,在学习后,通俗的来讲,Redux就是一个存储所有数据的大仓库。在使用React构建网页时,不同组件会用到各种各样的数据,当这些数据很多的时候,对于数据的管理会变得复杂,这时候可以使用Redux来集中管理所有的数据。
- Redux要遵循三大原则
-
唯一数据源
既然Redux是一个存储所有数据的大仓库,那么理所应当的Redux应用只需要管理一个全局的数据对象即可。
-
保持应用状态只读
Redux管理的数据不能直接进行修改,而是需要通过Redux自己去进行修改,下面会详细介绍这一部分。
-
改变数据需要通过纯函数来完成
纯函数满足两点要求:
- 对于相同的参数值,函数的返回值一定是一样的
- 函数的执行不会产生副作用,就是不能修改外部的对象或者输出到I/O设备
- Redux的主要组成
- action是一个普通的JavaScript对象,但是必须要包含一个type属性,其他的属性可以根据自己的需求来设计。想象这样一个场景,你在网上买了一个物品,结果发现地址写错了,你想要修改地址,但你肯定不能直接在发货单上修改,因为发货单是由商家填写的,这时你就把你想要修改地址的需求告诉商家,商家拿到了你的需求后修改发货单上的地址,action就是你的需求,type就是你需求的具体内容。例如
action{type:'修改地址'}
。 - reducer是响应action的操作,reducer就相当于是商家,当商家知道了你的需求后就会进行相应的操作。商家手上有所有的快递信息这些快递信息就是state,在编写reducer之前就已经有了全部的state信息。
- store是Redux中的唯一数据源,store需要通过createStore()函数创建,它负责沟通action和reducer,相当于让你和商家能进行沟通。
例子:
const state = { // 所有的快递信息保存在这里
地址: 北京
}
// actions
const action = {type: "修改地址"}; // 你的需求
// reducer
function reducer(state = state, action) { // 商家可以进行的操作
switch (action.type) {
case "修改地址":
return {...state, 地址: "上海"};
default:
return state;
}
}
// store
const store = redux.createStore(reducer)
store.dispatch(action); // 把你的需求告诉商家
总结一下:
你想要修改地址,此时你有了一个需求const action = {type: "修改地址"};
,store通过store.dispatch(action);
把你的需求告诉了商家,此时商家通过你需求的信息type: "修改地址"
知道了你想要修改地址,于是把快递的信息从北京变为上海。
现在知道了Redux的工作原理,如何在React中使用呢?
很简单,只需要两步即可。
-
使用connect函数,react-redux提供了一个connect函数,这个函数是用于把React组件和Redux的store连接起来的。
connect的返回值是一个高阶组件,把你想要被管理的组件传给这个高阶组件即可。connect的参数是两个函数mapStateToProps、mapDispatchToProps。- mapStateToProps
mapStateToProps接受一个state返回一个对象,因为你每个组件需要的数据并不一样,mapStateToProps可以让你在当前组件中获取到你想要的state信息。 - mapDispatchToProps
mapDispatchToProps接受一个dispatch返回一个对象,它的作用是定义当前组件可以发送哪些action来更新state。
- mapStateToProps
-
使用Provider组件,这个组件可以让React获取的Redux的store。
附上一个案例代码:
index.js
import React from 'react';
import {Provider} from 'react-redux';
import ReactDOM from 'react-dom';
import App from './App';
import {createStore} from "redux";
const defaultState = {
counter: 0
}
function reducer(state = defaultState, action) {
switch (action.type) {
case "ADD_NUMBER":
return { ...state, counter: state.counter + 1 };
default:
return state;
}
}
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
App.js
import React, {PureComponent} from 'react';
import Home from './Home';
export default class App extends PureComponent {
render() {
return (
<div>
<Home/>
</div>
)
}
}
Home.js
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
class Home extends PureComponent {
render() {
return (
<div>
<h2>counter: {this.props.counter}</h2>
<button onClick={e => this.props.increment()}>+1</button>
</div>
)
}
}
const action ={
type: "ADD_NUMBER"
};
const mapStateToProps = state => ({
counter: state.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
dispatch(action);
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Home);