美文网首页
redux实例

redux实例

作者: 小二子SAMA | 来源:发表于2019-03-08 10:43 被阅读0次

    一、原生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。

    相关文章

      网友评论

          本文标题:redux实例

          本文链接:https://www.haomeiwen.com/subject/muulpqtx.html