react-redux的基本用法

注意:讀懂本文須要具有redux基礎知識,css

註明:本文旨在說明如何在實際項目中快速使用react-redux,限於篇幅,本文對具體的原理並未作分析,請參考redux官網html

我一直覺得我寫了一篇關於react-redux的文章,昨天在翻個人博客時才發現沒有。vue

前幾天寫了vue的狀態管理 vuex,Vue中的狀態管理器 - Vuex,講了vue中狀態管理的用法,總體感受是很簡單的,react

狀態和路由都是官方本身整合的,不論是文檔仍是用來都比較順滑,而redux的門檻要比vuex高很多。webpack

題外話:爲何vue這麼好用你還要搞react呢,個人感受是,vue就像qq,react就像facebook,雖然均可以社交,可是味道不同,各有所好,web

另外react-native能夠作app目前vue不能,若是外包我選擇vue(快),要作一個長期的網站我會用react。vuex

說了一大堆,開始正文:npm

前面我寫了一篇文章:快速搭建一個vue開發環境,用到了vue官方的腳手架,一樣,react官方也有一個,相似功能的:create-react-app。redux

補充一點額外常識:vue中路由和狀態管理都是官方整合的,屬於官方庫,而在react中,只有react! 路由和狀態管理由第三方庫提供。react-native

全局安裝 create-react-app

npm install -g create-react-app

建立一個 test的項目

create-react-app test

經過這句話搭建的環境已經能夠正常跑起來了,集成了webpack,和熱加載,更以前vue搭建那個環境同樣,不過沒有路由和狀態管理,

這一篇我只講react+狀態管理,路由之後單獨寫,或者可能不用寫了,路由是很簡單的,看一下就知道怎麼用。

在項目目錄下執行 npm run start 項目就跑起來了,嘗試修改一下 src/App.js,頁面輝自動從新加載。

安裝redux

#說明:redux是一個通用狀態管理庫,能夠用於任何現代化框架,好比vue,react,angular等,不侷限於react,均可以直接使用redux。

在react中, 你除了能夠直接使用redux外,redux針對react推出了react-redux綁定,使用起來更規範和順滑。

本文要講解的是 react-redux的用法,並假設你已經有了redux的基礎概念。

npm install redux react-redux redux-thunk --save
// redux是核心,react-redux是react的綁定,redux-thunk是異步中間件

如今假設咱們網頁上有三個數據須要讓redux來管理,分別是 用戶的信息name,sex和系統的背景顏色bgcolor。

在src下新建actions目錄,在目錄下面新建userAction.js文件,

在src下新建reducers目錄,userReducer.js,rootReducer.js兩個文件,

在src下新建store.js 文件

整個流程是這樣的, view層獲取store中的數據渲染頁面,當在view中須要變動store中的數據的時候,就發送一個action過去,接收這個action的不是

store,而是reducer,reducer更改數據後更新state,在這個更新過程當中會觸發view層的渲染邏輯,而後view層從新渲染。

在一個頁面中會有不少操做要更改store中的數據,每個操做就對應一個action。

userAction.js 代碼:

export const nameAction = (name) =>{
    return {
        type: 'name',
        payload: name
    }
}

export const sexAction = () =>(dispatch)=>{
    setTimeout(()=>{
        dispatch({
            type: 'sex',
            payload: '男'
        })
    },2000)
}

第一個action是用來更更名字的,第二個action是用來更改性別的,這兩個action看起來有差別,第一個action返回一個對象,而第二個action

是一個高階函數,返回了一個函數。

第一個action是普通的操做,發送這個action後store中的數據立馬就會更新,而第二個action是用來處理異步數據的,能夠把這個地方的setTimeout替換成一個

網絡請求,好比我發送了一個更新資料的action,可是這個更新要從服務器動態獲取,那麼就只能用第二種方式,用第二種方式的前提是加載了thunk中間件,不然第二種方式會報錯。

userReducer.js 代碼:

let init = {
    'name': '張三',
    'sex': '女'
}
export default (state=init,action)=>{
    switch(action.type) {
        case 'name':
            state.name = action.payload
            return {...state}
        case 'sex':
            state.sex= action.payload
            return {...state}
        // 在沒有匹配的狀況下必定要返回舊的state
        default:
            return state
    }
}

reducer是純函數,第一個參數是當前state,第二個參數是接收的action,reducer經過action的type來判斷要處理的邏輯,

注意,reducer必定要返回新的state才能觸發view從新渲染,因此這裏返回的 {...state} 就是一個新對象,最後若是沒有匹配到

對應action,就返回舊的state。

rootReducer 代碼:

import {combineReducers} from 'redux'
// import systemReducer from './systemReducer'
import userReducer from './userReducer'

// 包含全部的計算函數
export default combineReducers({
    // system: systemReducer,
    user: userReducer
})

前面一個reducer是處理用戶板塊action的,一個網站有不少板塊,好比系統設置,若是把全部的處理都放到一個reducer中,那麼這個函數會很是龐大,

因此在文件組織上咱們把 reducer按照類型拆分紅多個reducer,最後用redux提供的combineReducer函數進行合併,rootReducer就是幹這事的

store.js 代碼:

import {createStore,applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/rootReducer'

export default function configureStore() {
    return createStore(
        rootReducer, 
        applyMiddleware(thunk)
    )
}

這段代碼是配置store的,經過createStore函數來建立一個store,第一個參數是 reducer,第二個參數是加載中間件,這個地方加載了thunk中間件,是redux官方提供的,

專門用來處理異步action,上面的userAction中設置sex時舊採用了異步的方式。

index.js 代碼:

import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import configureStore from './store';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
    <Provider store={configureStore()}>
        <App />
    </Provider>,
    document.getElementById('root'));

serviceWorker.unregister();

前面已經搞定了action,reducer,store,這個文件就是應用redux道項目中,主要關注 Provider和 store兩個地方,Provider時redux提供給react的包裝器,

store屬性用來注入狀態管理。這個地方就不解釋內部原理了,只要知道這麼用就行。

App.js 代碼:

import React, { Component } from 'react';
import {connect} from 'react-redux';
import {nameAction,sexAction} from './actions/userAction';
// import {bgcolorAction} from './actions/systemAction';
// import logo from './logo.svg';
import './App.css';

class App extends Component {

  componentDidMount() {}
  render() {
    return (
      <div className="App" >
        <header className="App-header" >
          {/* <p style={{color:this.props.system.backgroundColor}}> */}
          <p>
            name:{this.props.user.name} <br/>
            sex:{this.props.user.sex} <br/>
          </p>
          <button onClick={()=>this.props.name('利薩')}>更更名字</button>
          <button onClick={()=>this.props.sex()}>更改性別</button>
          {/* <button onClick={()=>this.props.bgcolor()}>更改顏色</button> */}
          <pre>
            { JSON.stringify(this.props) }
          </pre>
        </header>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  ...state
})
const mapDispatchToProps = dispatch=>({
  name: (name)=>dispatch(nameAction(name)),
  sex: ()=>dispatch(sexAction())
  // bgcolor: ()=>dispatch(bgcolorAction())
})

export default connect(mapStateToProps,mapDispatchToProps)(App);

這個地方關注 connect,mapStateToProps,mapDispatchToProps,

connect是redux提供的鏈接器,任何要使用redux這一套的view就必須使用connect鏈接,mapStateToProps是將store中的數據複製到

本view的props中,並且是實時同步的,

mapDispatchToProps 是將actioni複製到本view的props中,讓view擁有發送action的機會。

相關文章
相關標籤/搜索