Redux 入門級教程文檔

Redux 入門級教程文檔

在這裏我將用最淺顯易懂的語言給小夥伴們解釋一下 Redux, 而且一步步的教你們如何使用 Reduxcss

1、概念說明

一、什麼是 Redux, 爲何要使用 Redux

官網說明:Redux 是 JavaScript 狀態容器,提供可預測化的狀態管理。html

什麼意思呢?就是說隨着頁面複雜化,頁面上的不少數據須要保存,若路由跳轉後,前一個頁面的數據被銷燬會致使數據的丟失。node

若經過 url 傳遞,十分的麻煩,且要將每一個數據傳入組件中,寫起來也是十分的無腦浪費時間。react

二、爲何要使用 Redux

若是有個倉庫用來保存整個項目中須要被保留的數據,且組件中能夠直接拿到倉庫的數據。那麼這些數據將時刻保持一致,且清晰。git

2、環境搭建

一、安裝

首先咱們先用 create-react-app 建立一個 react 項目。npm

create-react-app redux-text,編程

安裝 reduxjson

npm install --save redux 或者 yarn add reduxredux

npm install --save react-redux 或者 yarn add react-reduxapi

二、概念簡單說明

這裏有幾個概念須要你們先稍微知道如下:

store: 咱們存放整個項目的一個倉庫,一個項目只能有一個倉庫,用來存放須要保存的數據。

state: store 中保存的數據。

action: 用戶在頁面上的操做是修改不到 store 裏的 state。頁面上的 view 要發生變化,就要在頁面上經過 action,去告訴 state 你要變化了。注意:這裏的 action 只是告訴倉庫的數據要變化了,而不是去變化數據!!

reducer: 接收 action 的請求,執行修改 store 裏的 state 的變化。

三、目錄結構

接下來咱們來建立幾個項目中須要用到的文件夾和文件,如下是目錄結構:

.
├── .gitignore
├── README.md
├── src                         
│   └── action                  	
│     ├── oneAction.js		
│     ├── twoAction.js		
│   └── components			
│   └── container
│			├── pageOne
|       ├──index.js
│   └── reducer	
│     ├── oneReducer.js
│     ├── twoReducer.js
│     ├── index.js
│   └── App.css		
│   └── App.js		
│   └── .....       
├── node_modules
├── package.json                
├── public            
複製代碼

3、搭建數據源

建立兩個數據源:

src/reducer/oneReducer.jssrc/reducer/twoReducer.js

const oneReducer = (
  state = {
    name: '航航',
    address: '福州'
  },
  action
) => {
  switch(action.type) {
    case 'setName': 
      return {
        ...state,
        name: action.payload.name
      }
    default: 
    return state;
  }
}

export default oneReducer;
複製代碼

這裏的純函數 oneReducer(state, action) 的兩個參數,分別表明了 store 下, 名爲 oneReducerstateaction

state: 存放了 oneReducer 下的全部數據源和初始值。

action: 經過不一樣的 action.type 去執行不一樣的操做,修改 state 數據

注意:每次修改 state, redux 並非去修改原來的 state,而是返回一個新的 state, 用新的 state, 去替換舊的 state

action.typesetName 時,咱們先將原先的 state 解構出來,並給 name 附上新值。

twoReducer.js 也是如此:

const twoReducer = (
  state = {
    age: 10,
  },
  action
) => {
  switch(action.type) {
    case 'setAge':
      return {
        ...state,
        age: 11,
      }
    default: 
    return state;
  }
}

export default twoReducer;
複製代碼

最後一步,整合全部的 reducer

import { combineReducers } from 'redux';

import OneReducer from './oneReducer';
import TwoReducer from './twoReducer';

export default combineReducers({
  OneReducer,
  TwoReducer,
})
複製代碼

combineReducers: 將全部的子 reducer 函數組成對象,提供一個新的 Reducer 函數

4、編寫頁面

咱們寫一個簡單的頁面,將兩個數據源的數據都展現出來。

一、建立倉庫

打開 src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import PageOne from './container/pageOne';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import Reducer from './reducer';

const store = createStore(Reducer);

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

serviceWorker.unregister();
複製代碼

createStore: 建立倉庫,用來存放 recuder 下的全部數據源。

Provider: redux 提供的一個組件,將 store 傳遞給其自組件。簡單說就是在整個項目的最外層包上一個組件,放進一個 store, 這樣就將 store 綁定進了項目中。

二、展現頁面

那麼如今咱們來專一於頁面 /src/container/pageOne/index.js 的編寫:

import React from 'react';
import { connect } from 'react-redux';

class PageOne extends React.Component {
  render() {
    const { oneReducer, twoReducer } = this.props;
    const { name = '', address = '' } = oneReducer;
    const { age = 0 } = twoReducer;
    console.log(oneReducer, twoReducer);
    return (
      <div> <div>name: {name}</div> <div>address: {address}</div> <div>age: {age}</div> </div>
    )
  }
}

const mapStateToProps = state => {
  const { oneReducer, twoReducer } = state;
  return {
    oneReducer,
    twoReducer,
  }
}

export default connect(mapStateToProps)(PageOne);
複製代碼

細細講解如下上面的知識點哈:

mapStateToProps: 獲取 store 倉庫下的數據源,這裏能夠打印如下 state, 看下輸出。

connect: 由 React Redux 庫提供的方法,將當前 Redux store state 映射到展現組件 props 中。

connect 作了性能優化,能夠避免不少沒必要要的重複渲染,好比,當 state 數據變更時,沒必要編寫 shouldComponentUpdate 方法來更新展現數據。

那麼至此,倉庫中的數據咱們就能夠經過 this.props 獲取到。

三、修改倉庫數據

store 的數據是沒法被修改的,這個保證了數據的穩定性。因此 redux 拋出一個 store.dispatch(action) 的事件,提供用戶修改 store 數據。

因此咱們繼續修改上面的 pageOne/index.js 頁面(簡寫):

class PageOne extends React.Component {
  
  changeName = (val) => {
    this.props.dispatch({
      type: 'setName',
      payload: {
        name: val
      }
    })
  }

  render() {
    return (
      <div> <div>name: {name}</div> <div>address: {address}</div> <div>age: {age}</div> <button onClick={ () => { this.changeName('change_name') }}>修更名字</button> </div>
    )
  }
}
複製代碼

如今去嘗試如下執行按鈕點擊事件吧。

好了,那麼至此一個狀態管理的操做就完成了。細心的小夥伴會發現 action 好像沒有用到?

那麼這個 action 究竟是作什麼的?

在我理解,就是把 dispatch 中的內容放到 action 中。

5、編寫 action

編寫 src/action/oneAction.js

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

export const setAge = (age) => ({
  type: 'setAge',
  age
})
複製代碼

修改下 pageOne/index.js 頁面(簡寫):

import { setName } from '../../action/oneAction';

class PageOne extends React.Component {
  changeName = (val) => {
    this.props.dispatch(setName(val))
  }
  ...
}
複製代碼

執行如下操做是否是發現也能夠呢?那麼爲何咱們還要來編寫 action 呢?

在我理解:是爲了更加註重 MVC 的模式,View 就應該注重 View 的展現邏輯,因此與 UI 無關的邏輯操做就交給 redux 來處理,體現代碼分層、職責分離的編程思想。

6、中間件-異步

一、代碼操做(第2點是知識點講解,小夥伴們要看哈)

因爲不少時候執行dispatch並不只僅是當即去更新reducer,這時須要執行其餘函數來知足項目需求,這些函數就是中間件,最後執行過一系列中間件後再去執行reducer

若是咱們調取服務端的接口,存在時間的延遲;或者說我想在 reducer 中也去調取其餘 reducer 的操做,行不行?

咱們來實驗一下:

咱們 oneAction.js 文件中再增長一個方法:

export const allChange = () => dispatch => {
  dispatch(setName('all_hang'));
  dispatch(setAge(10010));
}
複製代碼

pageOne.js 頁面上增長一個點擊事件(簡寫):

import { setName, allChange } from '../../action/oneAction';

class PageOne extends React.Component {

  changeAll = () => {
    this.props.dispatch(allChange())
  }

  render() {
    return (
      ...
      <div>
        <button onClick={ () => { this.changeAll() }}>修改所有</button>
      </div>
      ...
    )
  }
}
複製代碼

當咱們點擊按鈕就發現報錯了。看下 console 的報錯信息: Use custom middleware for async actions. 翻譯過來的意思是:使用自定義中間件進行異步操做。

說明在 reducer 中調用別的 reducer 的方法是能夠的,可是由於咱們缺乏中間件,因此執行報錯,如今咱們來把中間件加上:

修改代碼前咱們要編輯 cli,新增一條命令

yarn add redux-thunknpm install --save redux-thunk 導入 redux-thunk 庫。

編輯 src/index.js(簡寫):

如下爲簡寫代碼,頁面上原先的內容不刪除,只是新增了幾行代碼和修改了 createStore

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

const store = createStore(
  Reducer,
  applyMiddleware(
    thunkMiddleware
  )
);
...
...
複製代碼

那麼如今去執行如下 allChange() 事件看看效果,是否是發現頁面不報錯了,且 nameage 的數據也已經作了修改。

二、知識點

那麼咱們來說解如下 applyMiddlewarethunkMiddleware

什麼是 middleware

reduxmiddleware 是 發送 actionaction 到達 reducer 之間的第三方擴展,middleware 是架在 actionstore 之間的一座橋樑。

applyMiddleware 能夠看看官網的解釋。

Middleware 可讓你包裝 storedispatch() 方法來達到你想要的目的。

三、補充

最後來一個補充:

若是你想每次 dispatch 都可以在 console 打印日誌的話,手寫會很是的繁瑣。

那麼 redux 也提供了這樣一箇中間件,幫助咱們打印日誌。

鍵入 yarn add redux-logger 或者 npm install --save redux-logger 來導入 redux-logger 庫。

src/index.js 下加入如下代碼:

import { createLogger } from 'redux-logger'

const loggerMiddleware = createLogger()

const store = createStore(
  Reducer,
  applyMiddleware(
    thunkMiddleware,
    loggerMiddleware
  )
);
複製代碼

好了,去嘗試一下吧~

記得雙擊麼麼噠~

相關文章
相關標籤/搜索