React系列(七)——Redux的使用

前言

當(dāng)我們的前端項目功能點比較多歹苦,組件關(guān)系比較復(fù)雜時,單純的使用React原生的方法進(jìn)行組件數(shù)據(jù)的傳遞實現(xiàn)起來可能相對比較麻煩督怜,在這種場景下我們可能會需要有一個可以幫助我們做全局狀態(tài)管理的庫來解決這個問題殴瘦。Redux是一個專門用于做狀態(tài)管理的JS庫(不是react插件庫),他可以集中式管理React應(yīng)用中多個組件共享的狀態(tài)亮蛔。本篇文章將對redux以及react-redux的使用和功能進(jìn)行講解痴施,希望對各位讀者有所幫助。


一究流、先來了解Redux

(一)為什么要使用Redux

在講Redux的使用之前辣吃,我們不妨先回憶一下之前我們實現(xiàn)組件通信的方式都有哪些?
對于邏輯簡單的父子組件來說芬探,我們一般會直接使用props參數(shù)來傳遞組件中的狀態(tài)或者方法神得,而對于兄弟組件的通信,我們可以先把數(shù)據(jù)交由兄弟組件共有的父組件偷仿,再通過props參數(shù)傳遞到對應(yīng)的子組件哩簿。但這種做法較為麻煩,遇到嵌套層次比較深酝静,需要傳遞的屬性比較多時节榜,實現(xiàn)起來往往會大費周章。目前主流的解決思路主要有兩種别智,第一種是利用發(fā)布訂閱模式宗苍,組件間使用第三方庫進(jìn)行通信,常見的有庫有PubSubJS薄榛,第二種解決思路就是將組件的狀態(tài)交由一個對象全局進(jìn)行管理讳窟,任何組件都可以通過這個全局對象來獲取其他組件的值。
Redux就是第二種解決思路的解決方案敞恋,redux是一個專門用于做狀態(tài)管理的JS庫(不是react插件庫)丽啡。它可以用在react, angular, vue等項目中, 但基本與react配合使用。

(二)Redux的學(xué)習(xí)文檔

Redux的學(xué)習(xí)資料還是蠻多的硬猫,一般來說我們可以去中文的官方文檔去查看對應(yīng)的API以及其他特性的使用:

  1. 英文文檔: https://redux.js.org/
  2. 中文文檔: http://www.redux.org.cn/
  3. Github: https://github.com/reactjs/redux
(三)Redux的工作過程
Redux的工作原理圖

對于Redux的學(xué)習(xí)补箍,其實只要掌握了上面的工作流程圖,那么Redux的核心就掌握得差不多了啸蜜。原理圖中一共有4個對象馏予,ReactComponent指的是我們自定義的組件,而ActionCreators盔性、StoreReducers則是Redux中提出的新概念呢岗。
ActionCreator:用于創(chuàng)建action對象冕香,可以返回我們具體要對組件共享狀態(tài)進(jìn)行哪些操作蛹尝,比如說Redux幫助我們維護(hù)了A組件的count數(shù)據(jù),那么如果我們現(xiàn)在想要對count進(jìn)行+1的操作的話悉尾,我們就需要actionCreator幫助我們生成一個type為add突那,data為1的對象。

Store:store是Redux中的核心构眯,負(fù)責(zé)管理state狀態(tài)和調(diào)度Reducer愕难,當(dāng)我們把action交給store之后,store并不會直接對狀態(tài)進(jìn)行修改惫霸,而是交給對應(yīng)的reducer來對狀態(tài)進(jìn)行更新猫缭。

Reducer:reducer用于初始化狀態(tài)和加工狀態(tài),當(dāng)store指定reducer進(jìn)行更新狀態(tài)時壹店,reducer會根據(jù)原有的state和action進(jìn)行加工猜丹,返回新的state。

二硅卢、使用Redux來進(jìn)行狀態(tài)管理

(一)使用Redux來實現(xiàn)一個小需求

我們先來看這樣一個小案例:組件中有4個按鈕射窒,點擊后分別會對取下拉框的值對state中的值count進(jìn)行将塑、奇數(shù)加脉顿、異步加的操作。

export default class Count extends Component {
    state = {count:0}
    //加法
    increment = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        this.setState({count:count+value*1})
    }
    //減法
    decrement = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        this.setState({count:count-value*1})
    }
    //奇數(shù)再加
    incrementIfOdd = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        if(count % 2 !== 0){
            this.setState({count:count+value*1})
        }
    }
    //異步加
    incrementAsync = ()=>{
        const {value} = this.selectNumber
        const {count} = this.state
        setTimeout(()=>{
            this.setState({count:count+value*1})
        },500)
    }
    render() {
        return (
            <div>
                <h1>當(dāng)前求和為:{this.state.count}</h1>
                <select ref={c => this.selectNumber = c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>&nbsp;
                <button onClick={this.increment}>+</button>&nbsp;
                <button onClick={this.decrement}>-</button>&nbsp;
                <button onClick={this.incrementIfOdd}>當(dāng)前求和為奇數(shù)再加</button>&nbsp;
                <button onClick={this.incrementAsync}>異步加</button>&nbsp;
            </div>
        )
    }
}

上面這種方式是通過純react的方式來實現(xiàn)的点寥,下面我們換成使用redux來實現(xiàn):

步驟一:安裝redux
npm install --save redux
步驟二:定義專門用于處理count狀態(tài)的reducer

關(guān)于這一步艾疟,需要對一個小細(xì)節(jié)做一下解釋,當(dāng)store分發(fā)對應(yīng)的動作給reducer時开财,reducer一共會收到2個參數(shù)棕孙,分別是preStateaction炫掐,前者可以理解為當(dāng)前count的值,action即為即將對count進(jìn)行什么操作。但是在狀態(tài)初始化時弯院,此時由于count尚未存在,所以此時preState就會為undefined坞淮,而action將會是redux自動幫我們封裝好的一個action對象当纱,type為類似@@initxxxx這樣的字符串,value為空恤溶。所以我們需要在countReducer中針對初始化這種情況乓诽,給count的初始值進(jìn)行賦值。
可以參考下面這種方式咒程,嫌麻煩的話也可以直接在default中返回對應(yīng)的初始化值就行鸠天,比如這個案例就可以直接返回0。

const initState = 0 //初始化狀態(tài)
export default function countReducer(preState=initState,action){
    // console.log(preState);
    //從action對象中獲日室觥:type稠集、data
    const {type,data} = action
    //根據(jù)type決定如何加工數(shù)據(jù)
    switch (type) {
        case 'increment': //如果是加
            return preState + data
        case 'decrement': //若果是減
            return preState - data
        default:
            return preState
    }
}
步驟三:定義store.js文件奶段,暴露store對象

這里的話,使用了redux的核心APIcreateStore來創(chuàng)建store剥纷,傳入的參數(shù)是具體的reducer

import {createStore} from 'redux'
//引入為Count組件服務(wù)的reducer
import countReducer from './count_reducer'
//暴露store
export default createStore(countReducer)
步驟四:定義count狀態(tài)對應(yīng)的actionCreator
export const createIncrementAction = data => ({type: 'increment',data})
export const createDecrementAction = data => ({type: 'decrement',data})
步驟五:在Count組件中進(jìn)行共享狀態(tài)的獲取和修改

這里的話痹籍,我們使用了store.getState()來獲取count當(dāng)前的狀態(tài),在具體修改狀態(tài)的方法中使用了store.dispatch()來分發(fā)對應(yīng)的action晦鞋。

import React, { Component } from 'react'
//引入store蹲缠,用于獲取redux中保存狀態(tài)
import store from '../../redux/store'
//引入actionCreator,專門用于創(chuàng)建action對象
import {createIncrementAction,createDecrementAction} from '../../redux/count_action'

export default class Count extends Component {
    state = {carName:'奔馳c63'}
    //加法
    increment = ()=>{
        const {value} = this.selectNumber
        store.dispatch(createIncrementAction(value*1))
    }
    //減法
    decrement = ()=>{
        const {value} = this.selectNumber
        store.dispatch(createDecrementAction(value*1))
    }
    //奇數(shù)再加
    incrementIfOdd = ()=>{
        const {value} = this.selectNumber
        const count = store.getState()
        if(count % 2 !== 0){
            store.dispatch(createIncrementAction(value*1))
        }
    }
    //異步加
    incrementAsync = ()=>{
        const {value} = this.selectNumber
        setTimeout(()=>{
            store.dispatch(createIncrementAction(value*1))
        },500)
    }
    render() {
        return (
            <div>
                <h1>當(dāng)前求和為:{store.getState()}</h1>
                <select ref={c => this.selectNumber = c}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>&nbsp;
                <button onClick={this.increment}>+</button>&nbsp;
                <button onClick={this.decrement}>-</button>&nbsp;
                <button onClick={this.incrementIfOdd}>當(dāng)前求和為奇數(shù)再加</button>&nbsp;
                <button onClick={this.incrementAsync}>異步加</button>&nbsp;
            </div>
        )
    }
}

通過上面這種方式悠垛,我們就可以實現(xiàn)把Count組件的count屬性交由Redux來進(jìn)行管理了线定。但此時還存在一個問題:Redux雖然已經(jīng)幫我們進(jìn)行了狀態(tài)的管理,可是當(dāng)狀態(tài)的值發(fā)生變更時鼎文,redux并不會幫我們刷新頁面渔肩。所以常見的我們有兩種方式來解決這個問題:

方式一:在組件的componentDidMount鉤子中,定義刷新時機

下面的寫法表示拇惋,每當(dāng)store發(fā)生變更周偎,組件就會空調(diào)用一次setState(),從而讓組件執(zhí)行render方法

    componentDidMount(){
        store.subscribe(()=>{
            this.setState({})
        })
    }
方式二(常用):在最外層的index.js中為組件綁定更新動作

由于App組件是所有組件的父組件撑帖,一旦store中的狀態(tài)發(fā)生更新蓉坎,

ReactDOM.render(<App/>,document.getElementById('root'))

store.subscribe(()=>{
    ReactDOM.render(<App/>,document.getElementById('root'))
})
(二)引入constant.js文件進(jìn)行優(yōu)化

上面的代碼雖然實現(xiàn)了Redux的狀態(tài)管理,但在實際使用中胡嘿,我們會對action中的type進(jìn)行統(tǒng)一的常量封裝蛉艾,最終維護(hù)到一個constant.js文件中

步驟一:定義constant.js文件
/* 
    該模塊是用于定義action對象中type類型的常量值,目的只有一個:便于管理的同時防止程序員單詞寫錯
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
步驟二:在count_reducer.js中引入constant.js
/* 
    1.該文件是用于創(chuàng)建一個為Count組件服務(wù)的reducer衷敌,reducer的本質(zhì)就是一個函數(shù)
    2.reducer函數(shù)會接到兩個參數(shù)勿侯,分別為:之前的狀態(tài)(preState),動作對象(action)
*/
import {INCREMENT,DECREMENT} from './constant'

const initState = 0 //初始化狀態(tài)
export default function countReducer(preState=initState,action){
    // console.log(preState);
    //從action對象中獲冉陕蕖:type助琐、data
    const {type,data} = action
    //根據(jù)type決定如何加工數(shù)據(jù)
    switch (type) {
        case INCREMENT: //如果是加
            return preState + data
        case DECREMENT: //若果是減
            return preState - data
        default:
            return preState
    }
}
步驟三:在count_action.js文件中引入constant.js
/* 
    該文件專門為Count組件生成action對象
*/
import {INCREMENT,DECREMENT} from './constant'

//同步action,就是指action的值為Object類型的一般對象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//異步action面氓,就是指action的值為函數(shù),異步action中一般都會調(diào)用同步action兵钮,異步action不是必須要用的。
export const createIncrementAsyncAction = (data,time) => {
    return (dispatch)=>{
        setTimeout(()=>{
            dispatch(createIncrementAction(data))
        },time)
    }
}

表面看抽取的constant.js文件似乎反而增加了使用的復(fù)雜度舌界,但實際上當(dāng)變量比較多時掘譬,使用常量這種方式可以減少開發(fā)人員由于單詞拼寫錯誤導(dǎo)致的狀態(tài)更新失敗等問題。

三呻拌、異步action的定義

在之前的案例中葱轩,我們傳遞的action對象都是一般對象(plain Object)。但實際上,action還可以有另外一種類型: 異步action(其實也可以理解為是函數(shù)action)靴拱,也就是說我們對狀態(tài)的操作時放在異步的任務(wù)中完成复亏,同時,這個異步的任務(wù)不是組件自己來實現(xiàn)缭嫡,而是actionCreator來實現(xiàn)。需要注意的是

(1) 如果傳遞的action對象是函數(shù)抬闷,那么我們需要使用 redux-thunk 來對store進(jìn)行配置.
(2) 當(dāng)store調(diào)用dispatch方法的時候妇蛀,如果發(fā)現(xiàn)傳入的參數(shù)是函數(shù),那么store會幫我們調(diào)用這段函數(shù)笤成,并且傳遞給我們一個dispatch對象评架,供我們返回plain Object對象的時候直接調(diào)用。

上一小節(jié)的案例中炕泳,有一個按鈕的功能是異步加纵诞,異步的動作我們是在組件的方法中直接調(diào)用的,在本小節(jié)中培遵,我們將通過異步action來進(jìn)行實現(xiàn):

步驟一:引入redux-thunk

store默認(rèn)只支持一般對象浙芙,如果想要讓store支持函數(shù)的話,就需要借助redux-thunk來進(jìn)行調(diào)和籽腕。

npm i redux-thunk  
步驟二:在store.js中引用redux-thunk

這里的話嗡呼,需要在redux中導(dǎo)入一個新的函數(shù):applyMiddleware,幫助store支持中間件

/**
 *  這個js文件主要是用于對外暴露一個store對象
 *  store對象中需要傳入具體的reducer對象皇耗,reducer對象中定義了具體怎么操作數(shù)據(jù)的方法
 */

import {createStore, applyMiddleware} from 'redux'
import countReducer from './count_reducer'
// 引入 redux-thunk 用于支持異步action
import thunk from 'redux-thunk'
export default createStore(countReducer,applyMiddleware(thunk));
步驟三:在Count組件對應(yīng)的actionCreatoe中定義一個異步action

我們可以看到南窗,actionCreator一般的返回值是對象,我們這里的返回值是一個函數(shù)郎楼,默認(rèn)可以接收到dispatch對象万伤,同時我們在函數(shù)中進(jìn)行了異步(設(shè)置定時器)的操作。

 // 異步action
 export const createAsyncIncrementAction = (data,time) => {
     return (dispatch)=>{
         setTimeout(()=>{
            dispatch(createIncrementAction(data));
         },time)
     }
 }
步驟四:在自定義組件中使用異步action
import React, { Component } from 'react';
import store from '../../redux/store';
import {createDecrementAction,createIncrementAction,createAsyncIncrementAction} from '../../redux/count_action'

export default class Count extends Component {

    incrementAsync = () => {
        const { value } = this.countNum;
        store.dispatch(createAsyncIncrementAction(value*1,500));
    }

    render() {
        return (
            <div>
                <h2>總數(shù)為: {store.getState()}</h2>
                <select ref={a => this.countNum = a}>
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="3">3</option>
                </select>&nbsp;
               ...
                <button onClick={this.incrementAsync}>add async</button>&nbsp;
            </div>
        )
    }
}

我們可以看到呜袁,通過異步action我們就可以不需要自己在方法中手動寫異步函數(shù)了

四敌买、react-redux的使用

redux并不是react官方推出的狀態(tài)共享庫,但隨著使用人數(shù)的增加傅寡,react官方在后期也推出了**react-redux**來方便開發(fā)者更好的使用redux來進(jìn)行狀態(tài)的管理放妈。然后react-redux的使用和原先有些差別:
(1)提出了UI組件和容器組件的概念
(2)UI組件負(fù)責(zé)展示頁面和數(shù)據(jù),容器組件作為中間橋梁負(fù)責(zé)連接UI組件和redux之間的數(shù)據(jù)傳遞

react-redux雖然多了一些新概念荐操,相比于原先使用純粹的redux進(jìn)行狀態(tài)管理多了一定程度的復(fù)雜性芜抒,但是它也確實能夠簡化我們的一部分代碼。具體都簡化了哪些托启,我們不妨來看下面的實現(xiàn)步驟吧:

步驟一:下載react-redux
npm i react-redux
步驟二:定義容器組件

在已有UI組件的基礎(chǔ)上(這里我們以上一小節(jié)的組件作為UI組件)宅倒,我們新建一個和component同級的container目錄,里面存放我們的容器組件屯耸。創(chuàng)建容器組件主要依靠的是react-redux庫中的connect函數(shù)拐迁,connect函數(shù)是一個高階函數(shù)(返回值還是一個函數(shù))蹭劈,第一次傳入的參數(shù)是兩個函數(shù),分別對應(yīng)傳遞給組件的狀態(tài)和可供組件調(diào)整狀態(tài)的方法线召,第二次傳入的參數(shù)就比較固定了铺韧,就是我們的UI組件。

import {connect} from 'react-redux'
import CountUI from '../../components/Count'
import {createIncrementAction,createDecrementAction,createAsyncIncrementAction} from '../../redux/count_action'
/**
 * 由于 UI組件并不能直接獲取redux管理的狀態(tài)缓淹,所以這里的話需要由
 * 容器組價將狀態(tài)以及操作狀態(tài)的方法作為參數(shù)傳遞到connect()函數(shù)中
 */

 // 該方法返回的UI組件所需要獲取的redux管理的狀態(tài)屬性
 function mapStateToProps(state){
     return {count:state}
 }

  // 該方法返回的UI組件所需要的操作對應(yīng)狀態(tài)的方法
 function mapDispatchToProps (dispatch){
     return {
        increment: number => dispatch(createIncrementAction(number)),
        decrement: number => dispatch(createDecrementAction(number)),
        incrementAsync: (number,time) => dispatch(createAsyncIncrementAction(number,time))
     }
 }

// 作為參數(shù)傳入后哈打,UI組件可以通過props屬性讀取對應(yīng)的值
export default connect(mapStateToProps,mapDispatchToProps)(CountUI);

當(dāng)然了,我們這里可以有更加簡潔的寫法:
(1)把UI組件和容器組件都放在同一個文件中
(2)把connect第一次調(diào)用的入?yún)⑦M(jìn)行格式的優(yōu)化讯壶,返回的action會由store自動幫助我們進(jìn)行分發(fā)料仗。

import { connect } from 'react-redux'
import { createIncrementAction, createDecrementAction, createAsyncIncrementAction } from '../../redux/count_action'
import React, { Component } from 'react';

class Count extends Component {
  ...
}


// 作為參數(shù)傳入后,UI組件可以通過props屬性讀取對應(yīng)的值
export default connect(
    state => ({count: state }),
    {
        increment: createIncrementAction,
        decrement: createDecrementAction,
        incrementAsync: createAsyncIncrementAction
    }
)(Count);
步驟三:調(diào)整UI組件中獲取共享狀態(tài)和更新狀態(tài)方法的方式

其實這里的話伏蚊,就是由原來的直接導(dǎo)入storeactionCreator來獲取數(shù)據(jù)改為通過props進(jìn)行獲取立轧。

class Count extends Component {
    // 有了actionCreator , 我們就不需要自己再去定義action了
    increment = () => {
        const { value } = this.countNum;
        this.props.increment(value * 1)
    }
    decrement = () => {
        const { value } = this.countNum;
        this.props.decrement(value * 1)
    }
    incrementIfOdd = () => {
        const { value } = this.countNum;
        if (this.props.count % 2 === 1) {
            this.props.increment(value * 1)
        }
    }
    incrementAsync = () => {
        const { value } = this.countNum;
        this.props.incrementAsync(value * 1, 500)
    }
    render() {
        return (
            <div>
                <h2>總數(shù)為: {this.props.count}</h2>
                ...
          </div>
        )
    }
}
步驟四:在App組件中給Count組件傳入store對象

組件有了store對象躏吊,容器組件才可以獲取到store中的state以及dispatch對象

import React,{Component} from 'react';
import Count from './containers/Count';
import store from './redux/store'

export default class App extends Component{
    render(){
        return (
        <div>
            <Count store={store}/>
        </div>)
    }
}

容器組件一旦數(shù)量多了氛改,我們可能就不得不每個組件都要手動傳遞store屬性進(jìn)去,這樣比較麻煩颜阐,我們可以使用react-redux中自帶的<Provider>組件來幫助我們簡化這一步的操作平窘。具體的步驟如下:

(1)在最外層的index.js中使用<Provider>標(biāo)簽來包裹<App/>標(biāo)簽
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux'
import store from './redux/store'
ReactDOM.render(
    <Provider store={store}>
        <App/>
    </Provider>,document.getElementById('root'));
(2)原有的App.js文件可以不用傳遞store屬性了
import React,{Component} from 'react';
import Count from './containers/Count';
export default class App extends Component{
    render(){
        return (
        <div>
            <Count/>
        </div>)
    }
}

在這里,我們對使用react-redux進(jìn)行開發(fā)的優(yōu)勢和注意事項來做一個小結(jié):
(1)react-redux有著UI組件和容器組件的概念凳怨,UI組件并不能直接和redux進(jìn)行溝通瑰艘,而是要借助容器組件作為中間橋梁,獲取和操作組件共享狀態(tài)的方法都由容器組件來提供肤舞。這樣雖然一定程度上增加了使用的復(fù)雜性紫新,但是讓組件的職責(zé)變得更加清晰。
(2)使用react-redux可以自動實現(xiàn)狀態(tài)和頁面的聯(lián)動刷新李剖,讓我們不需要給APP組件或者其他自定義組件進(jìn)行store.subscribe()的動作更新綁定了芒率。
(3)針對react-redux有專門的開發(fā)者工具(瀏覽器插件)可以使用,幫我們更好地分析組件的狀態(tài)篙顺。

五偶芍、store中存在多個共享狀態(tài)的處理

在之前的案例中,無論是使用redux還是react-redux德玫,我們都只是對store只保存一個狀態(tài)的場景進(jìn)行演示匪蟀,但實際中稍微大一些的項目,基本上store中都是會存放多個狀態(tài)值的(否則使用也就失去了使用redux的意義)宰僧。
實際上材彪,當(dāng)store只存儲一個數(shù)值時,此時 store.state的值就是一個number類型的數(shù)字,要想滿足store可以存放多個數(shù)量段化、多種數(shù)據(jù)類型的狀態(tài)嘁捷,那么此時的store.state就需要是Object類型的才可以滿足。
假設(shè)我們現(xiàn)在在原有案例的基礎(chǔ)上新增了一個Person組件显熏,那么此時的store又應(yīng)該做出什么調(diào)整呢雄嚣?

步驟一:使用combineReducers函數(shù), 整合多個reducer喘蟆,再作為參數(shù)傳遞給store
import {createStore, applyMiddleware,combineReducers} from 'redux';
// 引入 redux-thunk 用于支持異步action
import thunk from 'redux-thunk';
import countReducer from './reducers/count';
import personReducer from './reducers/person';
// 注意现诀,如果是有多個狀態(tài)需要保存,那么在一開始調(diào)用combineReducers的時候履肃,就要設(shè)置好對象中各個狀態(tài)的key
const allReducers = combineReducers({
    count:countReducer,
    persons:personReducer
})
export default createStore(allReducers,applyMiddleware(thunk));
步驟二:調(diào)整對應(yīng)容器組件獲取狀態(tài)的方式

比如之前的Count組件就不再直接通過count = state的方式來獲取狀態(tài)了,而是通過count = state.count來獲取坐桩。

export default connect(
    state => ({count: state.count }),
    {
        increment: createIncrementAction,
        decrement: createDecrementAction,
        incrementAsync: createAsyncIncrementAction
    }
)(Count);

需要注意的是尺棋,在實際開發(fā)中,為了讓store.js文件更加清晰绵跷,我們常常會將各個狀態(tài)的reducer單獨抽取出來到一個文件中進(jìn)行整合膘螟,再導(dǎo)入到store.js文件中。

將所有reduer進(jìn)行抽取

將匯總好的reducer再導(dǎo)入到store.js中

說在最后:

Redux雖然可以幫助我們更好地管理組件間共享的狀態(tài)碾局,但redux除了需要額外的學(xué)習(xí)成本之外荆残,也一定程度上增加了項目的復(fù)雜性。如果只是小型項目净当,一般建議還是不引入Redux内斯,直接使用原生react特性可能更為方便。
react-redux其實只是官方為了方便我們更好地使用redux而推出的一個集成庫像啼,實際上可用可不用俘闯,只是說react-redux在某些方面也確實起到了簡化部分開發(fā)工作的作用。所以在實際應(yīng)用中忽冻,大家可以根據(jù)實際情況來使用真朗。

本篇文章的詳細(xì)案例代碼,可以在我的碼云上面下載:https://gitee.com/moutory/redux_test

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僧诚,一起剝皮案震驚了整個濱河市遮婶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌湖笨,老刑警劉巖旗扑,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異赶么,居然都是意外死亡肩豁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來清钥,“玉大人琼锋,你說我怎么就攤上這事∷钫眩” “怎么了缕坎?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長篡悟。 經(jīng)常有香客問我谜叹,道長,這世上最難降的妖魔是什么搬葬? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任荷腊,我火速辦了婚禮,結(jié)果婚禮上急凰,老公的妹妹穿的比我還像新娘女仰。我一直安慰自己,他們只是感情好抡锈,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布疾忍。 她就那樣靜靜地躺著,像睡著了一般床三。 火紅的嫁衣襯著肌膚如雪一罩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天撇簿,我揣著相機與錄音聂渊,去河邊找鬼。 笑死四瘫,一個胖子當(dāng)著我的面吹牛歧沪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莲组,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼诊胞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锹杈?” 一聲冷哼從身側(cè)響起撵孤,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竭望,沒想到半個月后邪码,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡咬清,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年闭专,在試婚紗的時候發(fā)現(xiàn)自己被綠了奴潘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡影钉,死狀恐怖画髓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情平委,我是刑警寧澤奈虾,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站廉赔,受9級特大地震影響肉微,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜡塌,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一碉纳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧馏艾,春花似錦村象、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽躁劣。三九已至迫吐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間账忘,已是汗流浹背志膀。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鳖擒,地道東北人溉浙。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像蒋荚,于是被迫代替她去往敵國和親戳稽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容