一、原生Redux
- 创建ActionType 和 Action
ActionType以常量表示,用于对Action的进行区别
Action接受状态信息作为输入,返回一个对象,对象中type是必须的,type的值是ActionType的一种
const TRAP_CHANGED = 'TRAP_CHANGED';
const STATE_CHANGED = 'STATE_CHANGED';
const STATION_NAME_CHANGED = 'STATION_NAME_CHANGED';
export const trapAction = text => ({
type: TRAP_CHANGED,
trapInfo: text,
})
export const stateAction = text => ({
type: STATE_CHANGED,
stateInfo: text,
})
export const stationNameAction = text => ({
type: STATION_NAME_CHANGED,
stationName: text,
})
- 创建Store
Store全局只有一个,所有需要进行全局管理的状态(State)都由Store进行维护。
Store方法介绍:
dispatch:可以用于action派发;
getState:用于获取Store上存储的所有状态
import {createStore} from 'redux';
import reducer from './reducer.js';
const initValues = {
stateInfo : '',
trapInfo : '',
stationName : ''
}
const store = createStore(reducer, initValues);
export default store;
createStore函数介绍:用于创建一个保存系统所有状态的Store
createStore(reducer, [preloadedState], [enhancer])
reducer:接受当前状态和action为输入,负责更新状态的纯函数,详见3
preloadedState:状态初始值
enhancer:Store Enhancer
- 创建reducer
通过判断Action的type字段,执行不同的逻辑处理,reducer是一个纯函数,不能修改传入的state的值
const reducer = (state = {}, action) => {
switch(action.type) {
case 'TRAP_CHANGED':
return {
...state,
stateInfo: action.stateInfo,
}
case 'STATE_CHANGED':
return {
...state,
trapInfo: action.trapInfo,
}
case 'STATION_NAME_CHANGED':
return {
...state,
stationName: action.stationName,
}
default:
return state;
}
}
export default reducer;
4.派发Action
import { stationNameAction } from '../../redux/action';
import store from '../../redux/store';
//保持Store和this.state同步
onChange = () => {
this.setState({
localStationName: store.getState().stationName
});
console.log(store.getState())
}
componentDidMount() {
store.subscribe(this.onChange);
}
componentWillUnmount() {
store.unsubscribe(this.onChange)
}
//派发
getStateName = () => {
getLocalStation()
.then(data => {
this.setState({
localStationName: data.localStationName,
})
store.dispatch(stationNameAction(data.localStationName));
})
.catch(e => {})
}
二、容器组件和展示组件
在React框架下,一个React组件主要负责如下两个功能:
1)与Redux Store打交道,读取Store状态,用来初始化组件状态;监测Store状态变化,当Store状态发生变化时,重新更新组件状态,驱动组件渲染;派发action更新Store状态;
2)根据当前的props和state渲染界面。
根据以上两点对React组件进行拆分,负责与Redux Store打交道的组件称为容器组件(Container Component,也称为聪明组件,Smart Component);负责渲染界面的组件,称为展示组件(Persentational Component,也称为傻瓜组件,Dumb Component)。容器组件为展示组件的外层组件,及父组件。容器组件通过props向展示组件传递信息。其中展示组件不包含状态。
// 容器组件
class CounterContainer extends Component {
render() {
<Counter caption={this.props.caption}
onIncrement = {this.onIncrement}
onDecrement = {this.onDecrement}
value = {this.state.value}
}
}
// 展示组件
function Counter(props) {
const {caption, onIncrement, onDecrement, value} = props;
return (
<div>
<button onClick={onIncrement}>+</button?
<button onClick={onDecrement}>-</button?
<span>{caption} count: {value}</span>
</div>
);
}
三、组件Context
由于在组件中直接导入Store是非常不利于组件复用的,所以最后只在系统调用最顶层的index.js中直接导入Store。
为了解决组件之间数据传递的问题(使用props需要传递太多层),所以react提供了Contex功能。
Context,就是“上下文”,可以实现树状组件上所有组件都能访问一个共有对象。
为了实现Context,
上级组件需要宣称自己支持context,并且提供一个函数来返回Context的对象;
该上级组件的所有子孙组件,只要宣称自己需要这个context,就可以通过this.context访问到这个共同的环境变量。
React通用Contex提供者组件——Provider 实现代码
import {PropTypes, Component} from 'react';
class Provider extends Component {
// 返回代表Context的对象
getChildContext() {
return {
store: this.props.store
}
}
render() {
// 渲染子组件
// 每个React组件的props中都包含一个特殊的属性children,代表的是子组件
return this.props.children;
}
}
// 指定Provider的childContextTypes属性
Provider.childContextTypes = {
store: PropTypes.object
}
Provider在系统中的使用如下,其中 <ControPanel />表示的是系统顶层组件,实现的功能是将context提供给应用中的所有组件。
import store from './store.js';
import Provider from './Provider.js';
ReactDOM.render(
<Provider store={store}>
<ControPanel />
</Provider>,
document.getElementById('root)
);
子组件为了能够访问到Context,必须对其contextType进行赋值,赋予的值应该和Provider的childContextType一样。
以子组件ConterContainer为例
CounterContainer.contextType = {
store: PropsType.object
}
// 访问context的值
getOwnState() {
return (
value: this.context.store.getState()
)
}
// 构造函数的第二个参数需要是context
constructor(props, context) {
super(props, context);
...
}
// 或者constructor可以简写为
constructor() {
super(...arguments);
...
}
四、React-Redux
React-Redux提供了上述的两个功能:
1)connect:连接容器组件和展示组件;
2)Provider:提供包含store的context。
connect函数简介:
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
mapStateToProps?: Function
mapDispatchToProps?: Function | Object
mergeProps?: Function
options?: Object
// mapStateToProps?:(state, ownProps?) => Object
将Store上的状态转换为内层展示组件的props
该函数用于订阅Redux的Store变化,每当Store发生变化,都会调用mapStateToProps函数,该函数的返回值必须是对象,返回的对象将用于合并到展示层组件的props中。当不需要订阅Store变化时,该函数的位置传入null或者undefined即可。ownProps表示外层容器组件的props,如果该函数包含第二个参数,则当容器组件的props发生变化时,也会调用该函数。
// mapDispatchToProps?: Object | (dispatch, ownProps?) => Object
将内层展示组件的用户动作转化为派送给Store的动作,即将内层展示组建暴露出来的props和dispatch函数的调用相关联
// binds on component re-rendering
<button onClick={() => this.props.toggleTodo(this.props.todoId)} />
// binds on `props` change
const mapDispatchToProps = (dispatch, ownProps) => {
toggleTodo: () => dispatch(toggleTodo(ownProps.todoId))
}
// mergeProps?: (stateProps, dispatchProps, ownProps) => Object
展示层组件最终props组成,默认是{ ...ownProps, ...stateProps, ...dispatchProps }
connet()是一个包装函数,接受一个展示层组件作为输入,返回一个容器组件。并且为展示组件注入props和dispatch。
网友评论