react漫谈 redux

redux简述

先来说讲redux是什么吧,咱们一般在react开发中都会这么说说,引入redux处理数据流,可是这里讲的redux已是通过二次封装的内容react-redux了,而他的原始形态才是redux,是一个不依赖react就能进行数据流处理的组件。而redux的又是脱胎于flux思想。flux是由facebook工程师提出的一种解决方案,他的名字是拉丁语的flow,主要是为了解决MVC架构存在的问题。他的核心思想是数据和逻辑永远单向进行流动。 讲到这里,咱们先描述下flux当时想要解决的问题(笑,也就是大名鼎鼎的MVC结构。react

MVC结构下代码的书写方式

首先,咱们先考虑下传统的react的数据处理的组件结构来实现一个博客的论坛评论app 论坛评论的app主要包含两个功能:json

  1. 评论展现区
  2. 评论编辑区

咱们尝试着去书写一个评论展现区的方案,专门用一个model组件来处理数据,再使用一个纯函数组件来进行业务逻辑组件的展现 代码以下:redux

import React,{Component,PropTypes}from 'react';
class CommentListContainer extends Component{
    constructor(props){
        super(props)
        this.state={loading:true,error:'',value:''}
    }
    
    componentDidMount(){
        this.props.promise.then(res=>res.json())
        .then(value=>this.setState({loading:false,value}))
        .catch(error=>this.setState({loading:false,error}))
    }
    
    render(){
        const{loading,error,value}=this.state
        if(loading){
            return <span>loading....</span>
        } else if(error.length!==0){
            return <span>Error:{error}</span>
        }else{
            return(
            <CommentList comments={list}
            )
        }
    }
}

function CommentList({comments}){
    return(
        <ul>
            {
                comments.map((v,i)=>(
                <li key={v.id}>{v.text}</li>
                ))
            }
        </ul>
    )
}


复制代码

以上是咱们在不使用redux的时候进行的react组件方案api

这样子看起来是和数据解耦了,可是实际上数据仍是在对应的组件内部进行保存,并不算完全的解耦数组

而以上的模型就是咱们咱们在MVC模型中讲述的Model和View,至于为何没有Controller,由于对于纯函数组件来讲,他不须要感知他作了什么内容,只须要知道用户的操做须要激发一个更改,因此若是有数据操做,也会放在Model中进行代码的书写,而View仅仅进行一个操做的动做 MVC Model负责同步数据,校验数据 View负责可视化,Controller负责链接View和Controller, MVC是上世纪80年代被提出的概念,直到2005年,他的问题被放大 那么MVC的问题是什么呢,下面用一张流程图来展现 promise

流程图
这是一张我在processon上绘制的流程图,由于model的set和get都是暴露在外的,因此view能够随意更改model的数值,一个view每每只会更改一个model,可是一个model更改了可能多个view的数值都被同时更改,并且model之间也能随意更改对方的

Flux的解决方案

讲完了mvc的解决方案来说讲flux的解决方案,用一张图表示刚刚说的核心思想,数据和逻辑永远单向流动浏览器

流程图
数据保证从action->dispather->store->view->action这样一个循环 这种渲染实际上是一种全面的渲染,可是由于使用了virtual DOM,并不会过多的影响性能,并且经过pureRender等方式保障节点的局部渲染。 可是flux并非万能的,从复杂场景来讲,好比浏览器的控制台,flux流程能比较好的下降复杂度

redux在实际中的运用

运用方式想必你们都很熟悉了,经过connect链接store,dispatch分发action来触发的机制 这里注重给你们介绍几种比较实用的中间件bash

  1. redux-form-utils 这个中间件的目的是为了减小建立表单的冗余代码 你们能够想象下原生react处理表单,下面只展现核心代码
handleChangeName(e){
    this.setState({
        name:e.target.value
    })
}

handleChangeAddress(e){
    this.setState({
        address:e.target.value
    })
}

render(){
    const {name,address}=this.state
    return(
    <form>
        <input  name="name" value={name} onChange={this.handleChangeName} />
        <input  name="address" value={address} onChange={this.handleChangeAddress} />
    </form>
    )
}
复制代码

能够看得出来,这个change事件的代码很是容易,并且大部分处理逻辑相似,这个时候用中间件能够怎么写antd

import {createForm } from 'redux-form-utils'
@createForm({
 form:'my-form',
 fields:['name','address']
})
class Form extends Component{
    render(){
        const {name,address}=this.props.fields;
        return(
            <form className='form'>
                <Input name='name' {...name} />
                <Input name='address' {...address} />
            </form>
        )
    }
}

复制代码

经过deractor+高阶组件的写法,内部封装了有关于form表单的处理来实现对代码的简写 用过antd的同窗确定发现了,这种写法其实就是antd的form表单的写法. redux-form-utils除了createForm还有个bindRedux,具体做用是在若是表单的数据是用来整个存放在redux中的表单数据架构

  1. redux-thunk 主要是以多参数的形式currying实现对函数的惰性求值。能够用来改造同步的dispatch为异步 核心代码以下:
function createThunkMiddleware(extraArgument){
    return({dispatch,getState})=>next=>action{
        if(typeof action==='function'){
            return action(dispatch,getstate,extraArgument)
        }
        return next(action)
    }
}
复制代码

当action为函数的时候,这个行为就被拦截了,而不是派发到reducer中去找到对应的action触发内容,这里的action就是一个thunk函数,将dispatch和getState派发到函数中 初始化thunk函数方法以下:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

const store = createStore(
  reducer,
  applyMiddleware(thunk)
);
复制代码

具体调用中能够这么写

let apis=(url,params)=>{
    return(dispatch,getState)=>{
        fetch(url,params).then(result=>{
            dispatch({
                type:'GET_WEATHER_SUCCESS',
                payload:result
            });
        }).catch(e=>{
            dispatch({
                type:'GET_WEATHER_ERROR',
                error:error
            })
        })
    }
}


store.dispatch(apis('https://xx.xx.xx.xx',{a:1,b:2}))

复制代码

后续再补充别的中间件

相关文章
相关标签/搜索