zoukankan      html  css  js  c++  java
  • 三、React全家桶(一)

    Reducer

    什么是Reducer?

    reducer就是一个纯函数,接收旧的 state 和 action,返回新的state

    之所以将这样的函数称之为 reducer,是因为这种函数与被传入  Array.prototype.reduce(reducer, ?initialValue)  里的回调函数属于相同的类型。保持 reducer 纯净非常重要。永远不要在 reducer里做这些操作:

    • 修改传入的参数
    • 执行有副作用的操作,如API请求或路由跳转
    • 调用非纯函数,如 Date.now() 或 Math.random()

    什么是reduce

    const array1 = [1, 2, 3, 4];
    // 类似累加:accumulator为total,currentValue为当前value
    const reducer = (accumulator, currentValue) => accumulator + currentValue;
    // 1 + 2 + 3 + 4 
    console.log(array1.reduce(reducer)); // expected output: 10
    // 5 + 1 + 2 + 3 + 4 
    console.log(array1.reduce(reducer, 5)); // expected output: 15

    函数聚合

    function f1() {
      console.log("f1");
    }
    function f2() {
      console.log("f2");
    }
    function f3() {
      console.log("f3");
    }

    现在想输出 : f1  f2  f3

    方法1:f1();f2();f3();

    方法2:f3(f2(f1()))

    方法3:

    function compose(...funcs){
      const len = funcs.length
      if(len === 0) return arg => arg
      if(len === 1) return funcs[0]
      return funcs.reduce((left, right)=>(...args)=>right(left(...args)))
    }
    compose(f1,f2,f3)()

    Redux上手

    Redux是JavaScript应用的状态容器。它保证程序行为一致性且易于测试。
     
    安装redux: npm install redux --save
    用一个累加器举例:
    1、需要一个store来存储数据
    2、store里的reducer初始化state并定义state修改规则
    3、通过dispatch一个action来提交对数据的修改
    4、action提交到reducer函数里,根据传入的action的type,返回新的state
     
    创建store ,src/store/ReduxStore.js
    import {createStore} from 'redux';
    
    function counterReducer(state=0, action){
      // console.log(state);
      switch (action.type){
        case "add":
          return state + 1
        default:
          return state
      }
    }
    
    const store = createStore(counterReducer)
    
    export default store

    创建 ReduxPage  

    import React, {Component} from 'react'
    import store from '../store/reduxStore';
    
    export default class ReduxPage extends Component {
      componentDidMount(){
        store.subscribe(()=>{
          // console.log('subscribe');
          // this.forceUpdate()
          this.setState({})
        })
      }
      render() {
        // console.log('ReduxPage', store);
        return (
          <div>
            <h1>ReduxPage</h1>
            <p>counter:{store.getState()}</p>
            <button onClick={() => store.dispatch({type: 'add'})}>add</button>
          </div>
        )
      }
    }

    检查点

    1、createStore 创建 store

    2、reducer 初始化、修改状态函数

    3、getState 获取状态值

    4、dispatch 提交更新

    5、subscribe 变更订阅

    react-redux

    每次都重新调用 render  和 getState 太low了,想用更react的方式来写,需要react-redux的支持

    npm install react-redux --save

    提供了两个api

    1、Provider 为后代组件提供store

    2、connect 为组件提供数据和变更方法

    全局提供store,index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import store from './store/reactReduxStore';
    import {Provider} from 'react-redux';
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>  
    , document.getElementById('root'));

    reactReduxStore.js

    import {createStore} from 'redux';
    
    function counterReducer(state=0, action){
      // console.log(state);
      switch (action.type){
        case "add":
          return state + 1
        case "minus":
          return state - 1
        default:
          return state
      }
    }
    
    const store = createStore(counterReducer)
    
    export default store

    ReactReduxPage.js

    import React, { Component } from 'react'
    import {connect} from 'react-redux';
    
    class ReactReduxPage extends Component {
      render() {
        console.log(this.props);
        const {counter, add, minus} = this.props
        return (
          <div>
            <h1>ReactReduxPage</h1>
            <p>counter:{counter}</p>
            <button onClick={add}>add</button>
            <button onClick={minus}>minus</button>
          </div>
        )
      }
    }
    export default connect(
      // mapStateToProps
      state=>{
        return {counter: state}
      },
      // mapDispatchToProps
      {
        add: ()=>{
          return {
            type: 'add'
          }
        },
        minus: ()=>{
          return {
            type: 'minus'
          }
        }
      }
    )(ReactReduxPage)

    异步

    Redux只是个纯粹的状态管理器,默认只支持同步,实现异步任务 比如延迟、网络请求,需要中间件的支持,比如我们试用最简单的redux-thunk和redux-logger

    npm install redux-thunk redux-logger --save

    应用中间件,store.js

    import {createStore, applyMiddleware} from 'redux';
    import logger from "redux-logger"
    import thunk from "redux-thunk";
    
    const store = createStore(counterReducer, applyMiddleware(logger, thunk))

    使用异步操作时的变化,ReduxTest.js

    const mapDispatchToProps = {
      add: ()=>{
        return {
          type: 'add'
        }
      },
      minus: ()=>{
        return {
          type: 'minus'
        }
      },
      asyAdd: () => dispatch =>{
        setTimeout(() => {
          // 异步结束后,手动调用 dispatch
          dispatch({
            type: 'add'
          })
        }, 1000);
      }
    }

    代码抽取

    抽离reducer和action

    1、抽离action

    action/reactReduxPage.js

    export const add = ()=>{
      return {
        type: 'add'
      }
    }
    export const minus= ()=>{
      return {
        type: 'minus'
      }
    }
    export const asyAdd= () => dispatch =>{
      setTimeout(() => {
        // 异步结束后,手动调用 dispatch
        dispatch({
          type: 'add'
        })
      }, 1000);
    }

    // 对应的ReactReduxPage文件直接引用

    import React, { Component } from 'react'
    import {connect} from 'react-redux';
    import {add, minus,asyAdd} from '../action/reactReduxPage'; // 此处直接引用

    class ReactReduxPage extends Component {
      render() {
        console.log(this.props);
        const {counter, add, minus, asyAdd} = this.props
        return (
          <div>
            <h1>ReactReduxPage</h1>
            <p>counter:{counter}</p>
            <button onClick={add}>add</button>
            <button onClick={minus}>minus</button>
            <button onClick={asyAdd}>asyAdd</button>
          </div>
        )
      }
    }
    const mapStateToProps = state => {
      return {
        counter: state
      }
    }
    const mapDispatchToProps = {
      add, 
      minus,
      asyAdd
    }
    export default connect(
      // mapStateToProps
      mapStateToProps,
      // mapDispatchToProps --- 直接引用
      mapDispatchToProps
    )(ReactReduxPage)

    2、抽离reducer

    store/counterReducer.js

    export default function counterReducer(state=0, action){
      // console.log(state);
      switch (action.type){
        case "add":
          return state + 1
        case "minus":
          return state - 1
        default:
          return state
      }
    }

    reactReduxStore.js调用

    import {createStore, applyMiddleware} from 'redux';
    import logger from "redux-logger"
    import thunk from "redux-thunk";
    import counterReducer from './counterReducer';
    
    const store = createStore(counterReducer, applyMiddleware(logger, thunk))
    
    export default store

    如果有多个中间件   ---  combineReducers

    reactReduxStore.js

    import {createStore, applyMiddleware, combineReducers} from 'redux'; 
    import logger from "redux-logger"
    import thunk from "redux-thunk";
    import counterReducer from './counterReducer';
    import counterReducer2 from './counterReducer';
    
    // 如果有多个中间件,则用combineReducers
    const store = createStore(
      combineReducers({
        counter: counterReducer,
        counter2: counterReducer2
      }), 
      applyMiddleware(logger, thunk)
    )
    
    export default store

    ReactReduxPage.js做出修改

    const mapStateToProps = state => {
      console.log(state); // {counter: 0, counter2: 0}
      // return需要做修改
      // return { counter: state }  
      return { counter: state.counter }
    }

    Redux拓展

    redux核心实现:

    • 存储状态state
    • 获取状态getState
    • 更新状态dispatch

    MyReduxPage.js

    import React, {Component} from 'react'
    import store from '../../store/MyReduxStore'; // 这里做出了修改
    
    export default class MyReduxPage extends Component {
      componentDidMount(){
        store.subscribe(()=>{
          this.setState({})
        })
      }
      render() {
        return (
          <div>
            <h1>ReduxPage</h1>
            <p>counter:{store.getState()}</p>
            <button onClick={() => store.dispatch({type: 'add'})}>add</button>
            <button onClick={() => store.dispatch({type: 'minu'})}>minu</button>
          </div>
        )
      }
    }

    MyReduxStore.js

    import {createStore} from '../kRedux';
    
    function counterReducer(state=0, action){
      // console.log(state);
      switch (action.type){
        case "add":
          return state + 1
        case "minu":
          return state - 1
        default:
          return state
      }
    }
    
    const store = createStore(counterReducer)
    
    export default store

    kRedux.js

    export function createStore(reducer){
      let currentState = undefined
      let currentListeners = []
      function getState(){
        return currentState
      }
      function dispatch(action){
        currentState = reducer(currentState, action)
        currentListeners.map(cl=>cl())
      }
      function subscribe(listener){
        currentListeners.push(listener)
      }
      dispatch({type: '@IMOOC/REDUX'}) // 这里随意写type值,本意是要初始化执行一次
      return {
        getState,
        dispatch,
        subscribe
      }
    }

    中间件实现

    kRedux.js

    export function createStore(reducer, enhancer){
      if(enhancer){ // 判断是否有增强器(中间件)
        return enhancer(createStore)(reducer)
      }
      let currentState = undefined
      let currentListeners = []
      function getState(){
        return currentState
      }
      function dispatch(action){
        currentState = reducer(currentState, action)
        currentListeners.map(cl=>cl())
      }
      function subscribe(listener){
        currentListeners.push(listener)
      }
      dispatch({type: '@IMOOC/REDUX'}) // 这里随意写type值,本意是要初始化执行一次
      return {
        getState,
        dispatch,
        subscribe
      }
    }
    
    // 中间件
    export function applyMiddleware(...middlewares) {
      return createStore => (...arg) => {
        const store = createStore(...arg)
        const midApi = {
          getState: store.getState,
          dispatch: store.dispatch
        }
        const chain = middlewares.map(mw=>mw(midApi))
        const dispatch = compose(...chain)(store.dispatch)
        return {
          ...store,
          dispatch
        }
      }
    }
    
    function compose(...funcs){
      const len = funcs.length
      if(len === 0) return arg=>arg
      if(len === 1) return funcs[0]
      return funcs.reduce((left, right)=>(...args)=>right(left(...args)))
    }

    MyReduxStore.js

    import {createStore, applyMiddleware} from '../kRedux';
    
    function counterReducer(state=0, action){
      // console.log(state);
      switch (action.type){
        case "add":
          return state + 1
        case "minu":
          return state - 1
        default:
          return state
      }
    }
    
    const store = createStore(counterReducer, applyMiddleware(logger))
    
    export default store
    
    function logger({dispatch, getState}){
      return dispatch=>action=>{
        console.log(action.type + "执行了~");
        return dispatch(action)
      }
    }
  • 相关阅读:
    AGC002
    ICPC 北美Mid Central 2019 Regional
    【洛谷 5020】货币系统
    【洛谷 1109】学生分组
    【洛谷 2915】奶牛混合起来
    【洛谷 4162】最长距离
    【YCOJ 3805】竞选
    【洛谷 2807】最长路
    【洛谷 2918】买干草Buying Hay
    【LOJ 10172】涂抹果酱
  • 原文地址:https://www.cnblogs.com/haishen/p/11699583.html
Copyright © 2011-2022 走看看