redux实例

2019-03-08  本文已影响0人  小二子SAMA

一、原生Redux

  1. 创建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,
})
  1. 创建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

  1. 创建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。

上一篇下一篇

猜你喜欢

热点阅读