三、React全家桶(一)

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)

}

}

以上是 三、React全家桶(一) 的全部内容, 来源链接: utcz.com/z/382924.html

回到顶部