摘要:原理分析是什么很多人認為必須要結合使用,其實并不是的,是狀態容器,只要你的項目中使用到了狀態,并且狀態十分復雜,那么你就可以使用管理你的項目狀態,它可以使用在中,也可以使用中在中,當然也適用其他的框架。
Redux原理分析
Redux是什么
很多人認為redux必須要結合React使用,其實并不是的,Redux 是 JavaScript 狀態容器,只要你的項目中使用到了狀態,并且狀態十分復雜,那么你就可以使用Redux管理你的項目狀態,它可以使用在react中,也可以使用中在Vue中,當然也適用其他的框架。一.redux的工作原理
先上圖(圖片源于網絡)
首先我們找到最上面的state
在react中state決定了視圖(ui),state的變化就會調用React的render()方法,從而改變視圖
用戶通過一些事件(如點擊按鈕,移動鼠標)就會像reducer派發一個action
reducer接收到action后就會去更新state
store是包含了所有了state,可以把他看做所有狀態的集合
當然,現在可能看不懂這在瞎說啥,但是等把這篇文章看完再來這個圖,和這段話,就會有恍然大明白的感覺
1.actionaction本質上就是一個對象,它一定有一個名為type的key 如{type: "add"},{type: "add"}就是一個action
但是我們只實際工作中并不是直接用action ,而是使用action創建函數,(千萬別弄混淆),
顧名思義action創建函數就是一個函數,它的作用就是返回一個action,如:
function add() { return {type: "add"} }2.reducer
reducer其實就是一個函數,它接收兩個參數,第一個參數是需要管理的狀態state,第二個是action。reducer會根據傳入的action的type值對state進行不同的操作,然后返回一個新的state,而不是在原有state的基礎上進行修改,但是如果遇到了未知的(不匹配的)action,就會返回原有的state,不進行任何改變。
function reducer(state = {money: 0}, action) { //返回一個新的state可以使用es6提供的Object.assign()方法,或擴展運算符(此方法需要babel-preset-state-3支持) switch (action.type) { case "+": return Object.assign({}, state, {money: state.money + 1}); case "-": return {...state, ...{money: state.money - 1}}; default: return state; } }3.store
你可以把store想成一個狀態樹,它包含了整個redeux應用的所有狀態。
我們使用redux提供的createStore方法生成store
import {createStore} from "redux"; const store = createStore(reducer);
store提供了幾個方法供我們使用,下面是我們常用的3個:
store.getState();//獲取整個狀態樹 store.dispatch();//改變狀態,改變state的唯一方法 store.subscribe();//訂閱一個函數,每當state改變時,都會去調用這個函數
接下來演示一個redux的完整應用,并且說明這三個方法該怎么用
import {createStore} from "redux"; //給初始狀態一個默認值:{money: 0} function reducer(state = {money: 0}, action) { //返回一個新的state可以使用es6提供的Object.assign()方法,或擴展運算符(此方法需要babel-preset-state-3支持) switch (action.type) { case "+": return Object.assign({}, state, {money: state.money + 1}); case "-": return {...state, ...{money: state.money - 1}}; default: return state; } } //action創建函數,返回了一個action function add() { return {type: "+"} } function subtraction() { return {type: "-"} } //創建單一狀態樹 const store = createStore(reducer); console.log(store.getState());//{money: 0},初始的狀態,沒有任何改變(通過getState來獲取目前的狀態) //store通過dispatch這個方法,并且傳入action作為參數,對store進行了改變 store.dispatch(add()); console.log(store.getState());//{money: 1},reducer接受到了 "+" 這個命令,就撿到了一塊錢 store.dispatch(subtraction()); console.log(store.getState());//{money: 0},reducer接受到了 "-" 這個命令,又掉了一塊錢 store.dispatch({type:"我是來搗亂的"}); console.log(store.getState());//{money: 0},reducer接受到了一個不識別命令,返回原有的state
這個時候我們就會發現幾個問題:
每次狀態改變的時候我們都要console.log()才能知道改變后的狀態,
action的type實際上就是一個字符串,如果我們需要進行項目維護,更改type的值,就需要在多處進行修改,變得十分麻煩。
這個時候我們就可以使用store.subscribe()來訂閱一個事件,代替我們在每次dispatch后都要console.log()后才能知道改變后的狀態
function listen() { console.log(store.getState()); } store.subscribe(listen);
將type維護成常量,這樣我們在日后的維護過程中只需要對常量進行維護就可以了,我們目前這個demo使用到type的地方太少可能感覺不到,可是在實際項目中這個方法卻非常的實用
const ADD = "+", SUBTRACTION = "-";
我們優化后的代碼如下:
import {createStore} from "redux"; //定義常量方便維護 const ADD = "+", SUBTRACTION = "-"; //給初始狀態一個默認值:{money: 0} function reducer(state = {money: 0}, action) { //返回一個新的state可以使用es6提供的Object.assign()方法,或擴展運算符(此方法需要babel-preset-state-3支持) switch (action.type) { case ADD: return Object.assign({}, state, {money: state.money + 1}); case SUBTRACTION: return {...state, ...{money: state.money - 1}}; default: return state; } } //action創建函數,返回了一個action function add() { return {type: ADD} } function subtraction() { return {type: SUBTRACTION} } //打印改變后的狀態 function listen() { console.log(store.getState()); } //創建單一狀態樹 const store = createStore(reducer); //訂閱listen,每次dispatch后都會執行listen,從而打印狀態(只有在執行dispatch后才會執行,狀態初始化的時候并不會執行) store.subscribe(listen); console.log(store.getState());//初始的狀態,沒有任何改變 //store通過dispatch這個方法,并且傳入action作為參數,對store進行了改變 store.dispatch(add()); store.dispatch(subtraction()); store.dispatch({type: "我是來搗亂的"}); /*控制臺的打印結果如下: {money: 0} {money: 1} {money: 0} {money: 0}*/
補充:
一個應用只能有一個store,這個時候就會有一個問題 ,如果有多個reducer分別來處理不同的狀態,而createStore是能接受一個reducer,這個時候我們就需要redux提供的combineReducers方法來將多個reducer結合成一個reducer
import {combineReducers} from "redux"; const reducerFamily=combineReducers({ reduceSon, reduceDaughter, reducerFather, reducerMother }) const store = createStore(reducerFamily);二.在React中使用redux
如果會react,那么也一定知道creact-react-app這個官方腳手架工具,首先使用creact-react-app創建一個項目,然后刪除src目錄下所有文件,接下來就可以愉快的敲代碼了。
在src下創建三個文件
index.js
import React from "react" import ReactDOM from "react-dom" import {createStore} from "redux" //引入我們的reducer和action創建函數 import {reducer, add, subtraction} from "./index.redux" import App from "./App" //創建store const store = createStore(reducer); //store.subscribe方法接受的參數是一個函數, // 所以將ReactDOM.render方法寫在一個函數內 function listen() { //將store,action創建函數分別以屬性的方式傳遞給子組件App ReactDOM.render(, document.querySelector("#root")); } //因為剛進入頁面沒有dispatch操作改變store, // 所以listen不會執行,我們需要手動調用一次 listen(); //重點,改變了store,頁面就會重新渲染, // 可以試試不寫這行代碼會是怎樣的效果 store.subscribe(listen);
App.js
import React from "react" export default class App extends React.Component { render() { //從屬性中獲取store,action創建函數 const {store, add, subtraction} = this.props; //獲取state let state = store.getState(); return} }我有{state.money}元
{/*通過store.dispatch方法改變store,從而頁面也會改變*/}
index.redux.js
//定義常量方便維護 const ADD = "+", SUBTRACTION = "-"; //給初始狀態一個默認值:{money: 0} export function reducer(state = {money: 0}, action) { //返回一個新的state可以使用es6提供的Object.assign()方法,或擴展運算符(此方法需要babel-preset-state-3支持) switch (action.type) { case ADD: return Object.assign({}, state, {money: state.money + 1}); case SUBTRACTION: return {...state, ...{money: state.money - 1}}; default: return state; } } //action創建函數,返回了一個action export function add() { return {type: ADD} } export function subtraction() { return {type: SUBTRACTION} }
效果圖
這樣我們就將redux和react結合了起來但是這樣我們可能會覺得麻煩,因為我們要將store和action創建函數傳給子組件,當我們的action比較多時,子組件比較多時,就需要將store和大量的action創建函數一層層的多次傳遞下去。這樣就會十分麻煩,因此我們就可以使用react-redux這個庫來幫助我們實現這個麻煩的過程
三.react-redux的使用 1.Providerreact-redux給我們提供了一個Provider組件,我們可以把這個組件寫在最外層,這樣被Provider包裹的所有組件都可以通過props來獲取state,無論組個組件藏得多么深。
而Provider組件只接受一個屬性,那就是store
那么我們index.js的代碼就變成下面這樣了:
import React from "react" import ReactDOM from "react-dom" import {createStore} from "redux" import {Provider} from "react-redux" import {reducer} from "./index.redux" import App from "./App" //創建store const store = createStore(reducer); ReactDOM.render(2.connect, document.querySelector("#root"));
當然,只有Provider組件是不夠的,我們還需要connect來幫助我們獲取state和action,沒錯,connect就是幫助我們獲取state和action的
那么問題就來了,我們的組件可不是需要項目中所有的state和action,只需要其中的一部分就可以了,所以connect會接受兩個參數,第一個參數它可以幫我們篩選state,第二個參數可以幫我們篩選action。
我們可以把這兩個參數寫成函數的形式,
參數1,
function mapStateToProps(state) { return { money: state.money } }
參數2,
function actionCreators() { return { subtraction, add } }
我們可以發現這兩個函數都是返回了一個對象,第一個函數返回了我們需要的state,第二個函數返回了我們需要的action創建函數
那么app.js 的代碼就變成這樣了:
import React from "react" import {connect} from "react-redux" import {add, subtraction} from "./index.redux" class App extends React.Component { render() { //因為connect的原因,state和action我們已經可以從屬性中獲取了 const {money, add, subtraction} = this.props; return} } //connect所需要的參數 //函數返回的我們需要的狀態,我們需要money,就從state中取出money //假如我們還需要house,就增加一個house:state.house function mapStateToProps(state) { return { money: state.money } } //connect需要的第二參數 //返回我們需要的action創建函數 function actionCreators() { return { subtraction, add } } //上面兩個函數返回的都是對象 //通過connect將state和action創建函數當做屬性傳遞給組件 export default App = connect(mapStateToProps, actionCreators())(App);我有{money}元
{/*這個時候不需要我們dispatch了*/}
如果熟悉es6裝飾器的語法那就更好了,可以使我們的代碼變得更優雅
app.js
import React from "react" import {connect} from "react-redux" import {add, subtraction} from "./index.redux" @connect( state => ({money: state.money}), { subtraction, add }) export default class App extends React.Component { render() { //因為connect的原因,state和action我們已經可以從屬性中獲取了 const {money, add, subtraction} = this.props; return} }我有{money}元
{/*這個時候不需要我們dispatch了*/}
看到這里再回頭看看最開始圖片,就能搞清楚redux的工作流程究竟是怎樣的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105959.html
摘要:調用鏈中最后一個會接受真實的的方法作為參數,并借此結束調用鏈。總結我們常用的一般是除了和之外的方法,那個理解明白了,對于以后出現的問題會有很大幫助,本文只是針對最基礎的進行解析,之后有機會繼續解析對他的封裝 前言 雖然一直使用redux+react-redux,但是并沒有真正去講redux最基礎的部分理解透徹,我覺得理解明白redux會對react-redux有一個透徹的理解。 其實,...
摘要:的返回值是函數,這個函數經調用,傳入參數,之后會在中間件鏈上進行傳遞,只要保證每個中間件的參數是并且將傳遞給下一個中間件。 了解了Redux原理之后,我很好奇Redux中間件是怎么運作的,于是選了最常用的redux-thunk進行源碼分析。 此次分析用的redux-thunk源碼版本是2.2.0,redux源碼版本是3.7.2。并且需要了解Redux原理 redux中間件都是由redu...
摘要:最近練手開發了一個項目,是一個聊天室應用。由于我們的項目是一個單頁面應用,因此只需要統一打包出一個和一個。而就是基于實現的一套基于事件訂閱與發布的通信庫。比如說,某一個端口了,而如果端口訂閱了,那么在端,對應的回調函數就會被執行。 最近練手開發了一個項目,是一個聊天室應用。項目雖不大,但是使用到了react, react-router, redux, socket.io,后端開發使用了...
閱讀 3658·2021-11-25 09:43
閱讀 652·2021-09-22 15:59
閱讀 1756·2021-09-06 15:00
閱讀 1779·2021-09-02 09:54
閱讀 699·2019-08-30 15:56
閱讀 1189·2019-08-29 17:14
閱讀 1850·2019-08-29 13:15
閱讀 891·2019-08-28 18:28