zoukankan      html  css  js  c++  java
  • React从入门到放弃(3):Redux简介

    安装

    npm i -S redux react-redux redux-devtools

    概念

    在redux中分为3个对象:Action、Reducer、Store

    Action

    1. 对行为(如用户行为)的抽象
    2. Action 就是一个普通 JavaScript 对象。如:{ type: 'ADD_TODO', text: 'Go to swimming pool' }(其中type字段是约定也是必须的)
    3. 作为Reducer的参数

    Reducer

    1. 一个普通的函数,用来修改store的状态。
    2. 函数签名:(currentState,action)=>newState
      1. 在 default 情况下返回currentState
      2. Object.assign({},state, { visibilityFilter: action.filter })(第一个参数不能为state) 等价于ES7的 { ...state, ...newState }
    3. redux 的 combineReducers 方法可合并reducer

    Store

    1. 代表数据模型,内部维护了一个state变量
    2. 两个核心方法,分别是getState、dispatch。前者用来获取store的状态(state),后者用来修改store的状态
    3. createStore(reducer) 可创建Store

    redux示例:

    import { createStore } from 'redux'
    
    // reducer
    function counter(state = 0, action) {
        switch (action.type) {
            case 'INCREMENT':
                return state + 1
            default:
                return state
        }
    }
    
    // state
    let store = createStore(counter); // 会调用
    
    // 监听
    store.subscribe(() =>
        console.log(store.getState())
    );
    
    // 调用reducer
    store.dispatch({ type: 'INCREMENT' });
    

    react-redux

    react的需求:

    1. 数据总是单向从顶层向下分发的
    2. 组件之间的沟通通过提升state:子组件改变父组件state的办法只能是通过onClick触发父组件声明好的回调
    3. state越来越复杂:单页应用的发展导致。包括服务器响应、缓存数据、本地生成尚未持久化到服务器的数据,也包括 UI 状态,如激活的路由,被选中的标签,是否显示加载动效或者分页器等等。

    react-redux 将react组件分为2种:展示组件 和 容器组件

    展示组件

    描述如何展示:负责UI样式的展示

    1. 数据来源:props
    2. 数据修改:通过props的回调函数
    3. 不直接使用redux

    容器组件

    描述如何运行:负责数据获取 和 状态更新

    1. 数据来源:redux state
    2. 数据修改:redux 派发action
    3. 直接使用redux

    react-redux 只有2个API:Provider 和 connect

    Provider

    <Provider store>

    1. 在原应用组件上包裹一层,使原来整个应用成为Provider的子组件
    2. 接收Redux的store作为props,内部通过context对象传递给子孙组件上的connect

    connect

    connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])(Component)

    作用:连接React组件与 Redux store

    mapStateToProps(state, ownProps) : stateProps

    1. 将 store 中的数据作为 props 绑定到组件上。
    2. 当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的 stateProps

    mapDispatchToProps(dispatch, ownProps): dispatchProps:将 dispatch(action) 作为 props 绑定到组件上

    mergeProps:指定 stateProps 以及 dispatchProps 合并到 ownProps 的方式。(默认使用Object.assign)

    connect是个高阶组件(HOC)大致源码:

    export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
      return function wrapWithConnect(WrappedComponent) {
        class Connect extends Component {
            constructor(props, context) {
                this.store = props.store || context.store
                this.stateProps = computeStateProps(this.store, props)
                this.dispatchProps = computeDispatchProps(this.store, props)
                this.state = { storeState: null }
                // 合并stateProps、dispatchProps、parentProps
                this.updateState()
            }
            shouldComponentUpdate(nextProps, nextState) {
                // 进行判断,当数据发生改变时,Component重新渲染
                if (propsChanged || mapStateProducedChange || dispatchPropsChanged) {
                    this.updateState(nextProps)
                    return true
                }
            }
            componentDidMount() {
                this.store.subscribe( () => this.setState({ storeState: this.store.getState() }) )
            }
            render() {
                return (
                    <WrappedComponent {...this.nextState} />
                )
            }
          }
          return Connect;
        }
    }
    

    react-redux示例:

    Counter.js

    import React, { Component } from 'react';
    import { createStore, bindActionCreators } from 'redux';
    import { Provider, connect } from 'react-redux';
    
    function clickReduce(state = { todo: 1 }, action) {
        switch (action.type) {
            case 'click':
                return Object.assign({}, state, { todo: state.todo + 1 });
            default:
                return state;
        }
    }
    
    let store = createStore(clickReduce);
    
    class Counter extends Component {
        render() {
            return (
                <div>
                    <div>{this.props.todo}</div>
                    <button onClick={this.props.clickTodo}>Click</button>
                </div>
            )
        }
    }
    
    // 方式1:
    export default connect(state => ({ todo: state.todo }),
        dispatch => ({ clickTodo: () => dispatch({ type: 'click' }) }))(Counter)
    
    // 方式2:
    export default connect(state => ({ todo: state.todo }),
        dispatch => bindActionCreators({ clickTodo: () => ({ type: 'click' }) }, dispatch))(Counter);
    

    index.js

    import React, { Component } from 'react';
    import { Provider } from 'react-redux';
    import { render } from 'react-dom';
    import Clock from './Clock'
    
    render((
    <Provider store={store}>
        <Counter />
    </Provider>), root);
    

    在redux中,我们只能dispatch简单的action对象。
    对应的在react-redux中,我们只能定义同步的reducer方法。
    下节将介绍在react-redux如何定义异步方法。让其更加适用于生产环境。

  • 相关阅读:
    HDU 1031 Design TShirt
    普利姆(Prime)算法
    hdu 2601 An easy problem
    克鲁斯卡尔(Kruskal)算法
    双调欧几里德旅行商问题hdu 2224 The shortest path POJ 2677Tour
    求一个数个各位相加的结果时
    C语言中各种类型的范围
    获取浏览器的scrollTop有几点小疑问
    学习,学习javascript
    各种翻页的效果! FILTER: revealTrans使用说明
  • 原文地址:https://www.cnblogs.com/neverc/p/9071065.html
Copyright © 2011-2022 走看看