這篇博客中咱們仍是以圖書館爲例子,介紹如何在React項目中使用Redux。若是你沒有看過我以前的博客,那麼這裏我就再闡述一下圖書館的例子:react
一個圖書館中有不少書,圖書館有管理員,咱們若是想要找書的時候,能夠詢問管理員書的具體位置,方便咱們快速拿到這本書;咱們想要借書或還書的時候,能夠將書交給管理員,而且出示本身的借書卡,讓管理員幫助咱們準確地登記,並將歸還的書放在準確地位置上。數據庫
經過以前的博客,咱們知道如下的對應關係:redux
明白了Redux元素和圖書館實例之間的對應關係,下面咱們開始動手寫這個實例的具體代碼。設計模式
咱們之因此要使用Redux,是由於要藉助Redux來管理項目中的數據,並且這些數據通常都有一個初始值,在實際的項目中,這個初始值通常都是經過API從數據庫中獲取。markdown
對於圖書館來講,確定也是有初始值的,好比初始狀態下圖書館在館的圖書和已借出書籍的記錄等。因此第一步,咱們須要初始化圖書館的數據,也就是初始化 State 。新建一個 initState.js 文件,代碼以下:函數
// initState.js 文件
const initState = {
// 當前狀態下,圖書館全部在館的圖書
allBooks: ["明朝那些事兒", "百年孤獨", "盜墓筆記", "紅樓夢", "西遊記", "三國演義"],
// 當前狀態下,圖書館已借出圖書的借閱記錄
outBooks: {
"20152008": ["法醫清明", "西遊記"],
"20152023": ["你好舊時光", "大秦帝國"],
"20152135": ["水滸傳", "魯迅文集"]
}
}
// 由於咱們是在一個單獨的文件中定義的這個變量,因此須要把這個變量導出
// 而後在其餘須要用的這個變量的文件中,導入變量
export default initState;
複製代碼
圖書館的圖書信息已經定義好了,如今就能夠再來聘用一個圖書館管理員來管理圖書信息。即定義一個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;
複製代碼
圖書館的圖書信息已經有了,圖書館管理員已經有了,如今咱們就能夠開始圖書館的正常營業了。
上面提到過,圖書館對應的是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;
複製代碼
到目前爲止,咱們已經成功建立了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;
複製代碼
使用Redux管理數據的時候,一個常見的需求是修改Store中的數據。
在Redux中,咱們不能直接修改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中的數據更新。
在項目中使用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的小白。另外筆記中有錯誤之處,還但願各位大佬予以指正。