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}))

複製代碼

後續再補充別的中間件

相關文章
相關標籤/搜索