Redux 學習筆記03——Redux 的使用實例

實例介紹

這篇博客中咱們仍是以圖書館爲例子,介紹如何在React項目中使用Redux。若是你沒有看過我以前的博客,那麼這裏我就再闡述一下圖書館的例子:react

一個圖書館中有不少書,圖書館有管理員,咱們若是想要找書的時候,能夠詢問管理員書的具體位置,方便咱們快速拿到這本書;咱們想要借書或還書的時候,能夠將書交給管理員,而且出示本身的借書卡,讓管理員幫助咱們準確地登記,並將歸還的書放在準確地位置上。數據庫

經過以前的博客,咱們知道如下的對應關係:redux

  • Store:對應的是整個圖書館
  • State:對應的是圖書館某一時刻的具體狀態。在這個事例中,咱們假設這個State是,圖書館某一時刻的在館圖書和已經借出書籍的記錄。
  • Action:對應的是圖書館用戶的請求,好比找書的請求,借書和還書的請求等。
  • Reducer:對應的是圖書館的管理員。咱們發出借書的請求,可是不知道如何登記,若是修改圖書館的相應數據。因而咱們就把處理請求的工做交給圖書館管理員來作。

明白了Redux元素和圖書館實例之間的對應關係,下面咱們開始動手寫這個實例的具體代碼。設計模式

圖書館實例的具體代碼

1. 初始化圖書館的State

咱們之因此要使用Redux,是由於要藉助Redux來管理項目中的數據,並且這些數據通常都有一個初始值,在實際的項目中,這個初始值通常都是經過API從數據庫中獲取。markdown

對於圖書館來講,確定也是有初始值的,好比初始狀態下圖書館在館的圖書和已借出書籍的記錄等。因此第一步,咱們須要初始化圖書館的數據,也就是初始化 State 。新建一個 initState.js 文件,代碼以下:函數

// initState.js 文件
const initState = {
    // 當前狀態下,圖書館全部在館的圖書
    allBooks: ["明朝那些事兒", "百年孤獨", "盜墓筆記", "紅樓夢", "西遊記", "三國演義"],	
    // 當前狀態下,圖書館已借出圖書的借閱記錄
    outBooks: {	
        "20152008": ["法醫清明", "西遊記"],            
        "20152023": ["你好舊時光", "大秦帝國"],              
        "20152135": ["水滸傳", "魯迅文集"]		 
    }
}

// 由於咱們是在一個單獨的文件中定義的這個變量,因此須要把這個變量導出
// 而後在其餘須要用的這個變量的文件中,導入變量
export default initState;
複製代碼

2. 定義Reducer,對接受的的Action進行數據處理

圖書館的圖書信息已經定義好了,如今就能夠再來聘用一個圖書館管理員來管理圖書信息。即定義一個Reducer,經過接收到的Action,對State作相應的修改。ui

他的工做就是接受圖書館用戶發出的請求,好比:找書,借書,還書等。根據不一樣的請求信息,對圖書館的數據進行相關處理,而後返回處理完成後圖書館的信息。this

好比用戶20152135要借一本《明朝那些事兒》,他會給管理員發送一個請求,管理員接受這個請求以後,會從在館書籍中,將《明朝那些事兒》刪除,同事會把《明朝那些事兒》添加到20152135用戶的借閱信息中。而後返回處理後圖書館的最新書籍狀態,方便下一次的查找和借閱。spa

用戶發出的請求對應到代碼中是一個對象,上述借書請求的對象以下:設計

const action_2 = {
    type: 'borrow_book',		
    title: '明朝那些事兒',
    userId: '20152135'
};
複製代碼

如今接收到了用戶發出的請求,咱們就要定義一個具體的Reducer,來處理這個請求。新建 reducer.js 文件,具體定義代碼以下:

// reducer.js 文件

// 由於要修改圖書館的State,因此這裏要引入
import initState from './initState.js'

function reducer(state = initState, action) {
    // 判斷請求的type,若是是borrow_book
    if(action.type === 'borrow_book') {
        let bookIndex = state.allBooks.indexof(action.title);
        state.allBooks.splice(bookIndex, 1);
        state.outBooks[action.userId].push(action.title);
        return state;
    }

    return state;
}

export default reducer;
複製代碼

經過上述代碼,咱們能夠看到,reducer是一個純函數,在這個函數裏面,只是對State進行修改,沒有其餘任何反作用。並且,只要是一樣的輸入,一定獲得一樣的輸出。

這裏咱們只定義一個處理action的邏輯,若是想要定義多個處理action的邏輯,能夠直接在這個函數中進行添加。好比如下代碼:

import initState from './initState.js'

function reducer(state = initState, action) {
    if(action.type === 'borrow_book') {
        // ...修改State的邏輯代碼
        return state;
    }
    if(action.type === 'return_book') {
        // ...修改State的邏輯代碼
        return state;
    }
    if(action.type === 'search_book') {
        // ...修改State的邏輯代碼
        return state;
    }

    return state;
}

export default reducer;
複製代碼

3. 定義Store,開始圖書館的正常營業

圖書館的圖書信息已經有了,圖書館管理員已經有了,如今咱們就能夠開始圖書館的正常營業了。

上面提到過,圖書館對應的是Redux的Store,下面咱們須要作的就是根據Redux來建立Store。定義很是簡單,新建 Store.js 文件,代碼以下:

// Store.js 文件
import { createStore } from 'redux'     // 引入redux包中的建立函數
import reducer from './reducer'     	// 引入定義的reducer

const store = createStore(reducer)

export default store;
複製代碼

4. 引入Store,使用Redux中的數據渲染頁面

到目前爲止,咱們已經成功建立了Store,如今就能夠在React組件中引入Store,開始使用Redux管理咱們的數據了。下面給出一個小實例:經過Redux中的數據,來渲染頁面。直接在App.jsx 文件中進行書寫代碼。

import React from 'react';
import store from './Store.js'

class App extends React.Component {
    constructor(props) {
        super(props);
        // 經過getState() 函數獲取Store這一時刻的State
        this.state = store.getState();  
    }
    render() {
        return (
            <div> <p>圖書館在館圖書:</p> <ul> {this.state.allBooks.map(book => <li key={book}>{book}</li>)} </ul> { Object.keys(this.state.outBooks).map(userId => { return ( <div key={userId}> {userId}: { this.state.outBooks[userId].join(" ") } </div> ) }) } </div>
        );
    }
}

export default App;
複製代碼

5. 修改Store中的數據

使用Redux管理數據的時候,一個常見的需求是修改Store中的數據。

在Redux中,咱們不能直接修改Store中的數據,須要走一個流程:

  1. 發送一個Action請求
  2. Reducer接收這個請求,經過定義好的函數來修改Store中的數據

因此,想要在一個組件中修改Store的數據,咱們首先須要定義一個Action對象,好比前面提到的這個Action:

const action_2 = {
    type: 'borrow_book',		
    title: '明朝那些事兒',
    userId: '20152135'
};
複製代碼

Action定義好以後,咱們須要在組件中使用 Store.dispatch()方法來觸發這個Action對象。下面展現一個很是簡單的例子:

import React from "react";
import Store from "../redux/Store";

class AddNewBooks extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allBooks: Store.getState().allBooks,
      newBookName: ""
    };
  }

  setNewBooksName = (val) => {
    this.setState({
      newBookName: val
    });
  }

  addNewBooks = () => {
    // 定義Action
    const addBooks = {
      type: "ADD_BOOKS",
      newBookName: this.state.newBookName
    }
    // 觸發Action
    Store.dispatch(addBooks);
  }

  render() {
    return (
      <> <div className="add-books-panel"> <input value={this.state.newBookName} type="text" onChange={(e) => { this.setNewBooksName(e.currentTarget.value) }} /> <button onClick={this.addNewBooks}>Add New Boos</button> </div> </>
    )
  }
}

export default AddNewBooks;
複製代碼

觸發Action以後,Reducer中的函數會接收到這個請求,而後根據定義好的邏輯代碼對Store中的書進行處理,好比這樣的Reducer函數:

import InitialState from "./InitialState";

const reducer = (state = InitialState, action) => {
  if (action.type === "ADD_BOOKS") {
    return {
      ...state,
      allBooks: [...state.allBooks, action.newBooks]
    };
  }
  
  return state;
}

export default reducer;
複製代碼

Reducer函數對Store中的書處理以後,會返回一個新的state,這個state就是當前Store的一個快照,也就是當前Store中的最新數據。

如此一來,咱們就完成了redux中的數據更新。

6. 監聽Store數據變化,刷新頁面

在項目中使用Redux的時候,還有這樣一個常見的情形:當Store中的數據發生變化的時候,其餘組件中的內容要可以實時更新。其實作大這一點很是簡單,只須要使用 Store.subsctibe() 方法便可實現。

這個方法接受一個函數做爲參數,一旦state有變化,Redux就會調用這個函數。若是你有了解過設計模式,能夠直到,Redux使用到了 "發佈-訂閱" 模式。經過subsctibe方法訂閱Store的更新,一旦Store發佈了更新,Redux就會執行訂閱函數中的內容。

下面來看這個方法的使用實例:

import React from 'react'
import Store from "../redux/Store";

class AllBooks extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      allBooks: Store.getState().allBooks
    };
    
    // 訂閱Redux Store中的數據動態,一旦有變化,就會執行這個函數中的內容 
    Store.subscribe(() => {
      this.setState({
        allBooks: Store.getState().allBooks
      });
    });
  }

  render() {
    return (
      <div className="books-panel"> { this.state.allBooks.map(_book => <p className="book-item" key={_book}>{_book}</p>) } </div>
    )
  }
}

export default AllBooks;
複製代碼

寫在後面

好了,這就是關於這個Redux使用實例所有內容啦。但願這篇淺顯的筆記可以幫助到剛剛接觸Redux的小白。另外筆記中有錯誤之處,還但願各位大佬予以指正。

相關文章
相關標籤/搜索