徹底讓你理解redux

2021-02-20 全棧前端精選

臨危受命,一周各種熬夜突擊redux,好吧,剛開始真的各種香菇藍瘦,前天還熬到凌晨五點多,寫了點demo,有點感覺,一點點記錄下。這裡簡單介紹下Redux以及其與react結合的使用方法

我們為什麼需要Redux,什麼是Reduxstate

state才是真正的前端資料庫,它存儲著這個應用所有需要的數據。 這裡拿一個簡單的例子說明下,為什麼說簡單的例子呢,因為簡單到不應該使用redux。。。 運行效果如圖(學習redux這個例子被介紹爛了):

項目的運行效果大家應該能猜到哈,猜不到的clone下項目几几運行下:-) 所以這裡的如說問你,這個應用應該存在數據裡什麼數據呢?對的,就一個count,所以資料庫就存一個count就可以了,同理,這個應用的state其實就醬紫: 

注釋錯了,是count值為3 .╥﹏╥...

這裡展示的不是很明顯,可以拿我們下一篇博客的demo來查看下它的 state

所以說道這裡,大家對於state就已經明白了,需要說明一下的是,一個應用只應該有一個state。對,不管多大,就一個!

action

既然這些state已經有了,那麼我們是如何實現管理這些state中的數據的呢,當然,這裡就要說到action了。 什麼是action?E:action,中:動作。 是的,就是這麼簡單。。。
只有當某一個動作發生的時候才能夠觸發這個state去改變,那麼,觸發state變化的原因那麼多,比如這裡的我們的點擊事件,還有網絡請求,頁面進入,滑鼠移入。。。所以action的出現,就是為了把這些操作所產生或者改變的數據從應用傳到store中的有效載荷。 需要說明的是,action是state的唯一來源。
action也沒有什麼神秘,本質上就是一個JavaScript對象,但是約定的包含type屬性(你總得告訴你這個action是啥嘛),可以理解成每個人都要有名字一般。除了type屬性,別的屬性,都可以DIY~
那麼這麼多action一個個手動創建必然不現實,一般我們會寫好action creator,即action的創建函數。調用action creator,給你返回一個action。

比如這個counter應用,我們就有兩個action,一個decrement,一個increment。 所以這裡的action creator寫成如下:

export function decrement() {    return{        type:DECREMENT_COUNTER    }}export function increment(){    return{        type:INCREMENT_COUNTER    }}

好吧,藏也藏不住了,你也發現了這裡有另外兩個按鈕,幹嘛的?奇數是點擊+1、延遲+1,對應的action creator:

export function incrementIfOdd(){    return(dispatch,getState)=>{        const {counter} = getState();        if(counter%2==0) {            return;        }        dispatch(increment());    }}export function incrementAsync() {    return dispatch => {        setTimeout(() => {            dispatch(increment());        }, 1000);    };}

好吧,又被你發現了,不是說action creator返回的是一個action對象麼,你這返回的什麼鬼?這裡留個疑惑好吧,簡單的解釋, 為什麼可以這麼用呢,因為我用了中間件呀~(後續會介紹)

為了減少樣板代碼,我們使用單獨的模塊或文件來定義 action type 常量

export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'; export const DECREMENT_COUNTER = 'DECREMENT_COUNTER';

這麼做不是必須的,在大型應用中把它們顯式地定義成常量還是利大於弊的。

如果我都快把action說完了你還是不懂action是什麼的話,你就理解成,一個可能!改變state的動作包裝。

reducer

既然這個可能改變state的動作已經包裝好了,那麼我們怎麼去判斷並且對state做相應的改變呢?對,這就是reducer幹的事情了。 從一開始我們就說明下一個概念:

reducer決定了state的最終格式。

reducer是一個純函數,也就是說,只要傳入參數相同,返回計算得到的下一個 state 就一定相同。沒有特殊情況、沒有副作用,沒有 API 請求、沒有變量修改,單純執行計算。

reducer對傳入的action進行判斷,然後返回一個通過判斷後的state,這就是reducer的全部職責。 從代碼可以簡單地看出:

import {INCREMENT_COUNTER,DECREMENT_COUNTER} from '../actions';export default function counter(state = 0,action) {    switch (action.type){        case INCREMENT_COUNTER:            return state+1;        case DECREMENT_COUNTER:            return state-1;        default:            return state;    }}

這裡我們就是對增和減兩個之前在action定義好的常量做了處理。

對於一個比較大一點的應用來說,我們是需要將reducer拆分的,最後通過redux提供的combineReducers方法組合到一起。 如此項目上的:

const rootReducer = combineReducers({    counter});export default rootReducer;

雖然這裡我們就一個counter (ಥ_ಥ) 但是道理你懂得。

這裡你要明白:每個 reducer 只負責管理全局 state 中它負責的一部分。每個 reducer 的 state 參數都不同,分別對應它管理的那部分 state 數據。 combineReducers() 所做的只是生成一個函數,這個函數來調用你的一系列 reducer,每個 reducer 根據它們的 key 來篩選出 state 中的一部分數據並處理, 然後這個生成的函數再將所有 reducer 的結果合併成一個大的對象。

store

store是對之前說到一個聯繫和管理。具有如下職責

維持應用的 state;

提供 getState() 方法獲取 state

提供 dispatch(action) 方法更新 state;

通過 subscribe(listener) 註冊監聽器;

通過 subscribe(listener) 返回的函數註銷監聽器。

後面兩個不怎麼用哈~

再次強調一下 Redux 應用只有一個單一的 store。當需要拆分數據處理邏輯時,你應該使用 reducer 組合 而不是創建多個 store。 store的創建通過redux的createStore方法創建,這個方法還需要傳入reducer,很容易理解:畢竟我需要dispatch一個action來改變state嘛。 應用一般會有一個初始化的state,所以可選為第二個參數,這個參數通常是有服務端提供的,傳說中的Universal渲染。後面會說。。。 第三個參數一般是需要使用的中間件,通過applyMiddleware傳入。

說了這麼多,action,store,action creator,reducer關係就是這麼如下的簡單明了: 

接合react-redux的使用

說到react-redux,必然想到react和redux,是的,react-redux正是redux和react的橋梁工具。

react-redux將組建分成了兩大類,UI組建和容器組建。 簡單的說,UI組建負責美的呈現,容器組件負責來幫你盛著,給你"力量"

好吧,官方點: UI 組件有以下幾個特徵:

只負責 UI 的呈現,不帶有任何業務邏輯

沒有狀態(即不使用this.state這個變量)

所有數據都由參數(this.props)提供

不使用任何 Redux 的 API

如:

export default class Counter extends Component{    render(){        const {counter,increment,decrement,incrementIfOdd,incrementAsync} = this.props;        return(            <p>                Clicked:{counter} times                {'  '}                <button onClick={increment}>+</button>                {'  '}                <button onClick={decrement}>-</button>                {'  '}                <button onClick={incrementIfOdd}>increment if Odd</button>                {'  '}                <button onClick={incrementAsync}>increment async</button>            </p>        )    }}

容器組件特性則恰恰相反:

負責管理數據和業務邏輯,不負責 UI 的呈現

帶有內部狀態

使用 Redux 的 API

如:

class App extends Component{    render(){        const {counter,increment,decrement,incrementIfOdd,incrementAsync} = this.props;        return(            <Counter                counter={counter}                increment={increment}                decrement={decrement}                incrementIfOdd={incrementIfOdd}                incrementAsync={incrementAsync}/>        )    }}App.propTypes = {    counter:PropTypes.number.isRequired,    increment:PropTypes.func.isRequired,    decrement:PropTypes.func.isRequired,    incrementIfOdd:PropTypes.func.isRequired,    incrementAsync:PropTypes.func.isRequired};export default connect(    state=>({        counter:state.counter    }),    ActionCreators)(App);

說到這裡大家應該都懂,那麼問題來了,redux和react如何產生點關係呢??不難想到,如果產生關係肯定只要跟容器組件產生關係就可以了,畢竟他是react這些組件的老祖宗。 那麼如何產生關係呢??對的,就是上面代碼裡的,react-redux中的connect方法。

connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的業務邏輯。前者負責輸入邏輯,即將state映射到 UI 組件的參數(props), 後者負責輸出邏輯,即將用戶對 UI 組件的操作映射成 Action。

比如這樣:

export default connect(  state => ({ counter: state.counter }),  ActionCreators)(Counter);

因為作為組件,我們只要能拿到值,能發出改變值得action就可以了,所以mapStateToProps和mapDispatchToProps正是滿足這個需求的。

當時對這個connect也是好一頓理解

這麼通俗的說你該明白了吧

可以吧所有的組件想像成裝在一個罐子裡,這個罐子使用container做的,然後這個罐子的唯一的口就是裡面的東西想要去改變的唯一途徑。 說白了,這個口,就是connect,而redux中的所有的組件都是在罐子外面的。

reducer是改變state的,state就可以可以理解成組件的糧食,需要的時候redux就把糧食通過dispatch投入到罐子裡。 那麼我怎麼知道你需要呢?所以我們之間得有個約束,你喊一聲餓了,我就知道你要吃飯了,你喊一聲渴了,我就知道你要喝水了。 這些動作,就是你發出的action,喊得詞語,餓了,渴了,就是action.type,然後redux拿給軍事reducer解讀下,到底給罐子裡投入什麼。

不知道這麼通俗的解釋有沒有說明白  (T_T) 

所以這樣看來,組件通過container包裝以後和redux就可以說是完全隔絕了,組件就是做組件的事情,redux就是做redux的事情。中間的樞紐是connect。 這也就說明了,redux並不是只服務我們react噠~也即是我這一套邏輯在罐子外面,罐子裡面是什麼其實我並不是很在意。。。只要我們預定好action和state就可以了。

所以。。。redux也並沒有特別神秘的地方。 當然,這裡只是簡單的說了下redux的簡單概念,並沒有特別深入的講解。 關於redux的異步操作,以及在服務端的運行(node),universal渲染,結合react-router的使用等等等的功能,咱再慢慢了解慢慢研究慢慢總結哈~

ヾ(^▽^ヾ)

相關焦點

  • 深度剖析github上15.1k Star項目:redux-thunk
    >這三個方面來帶大家徹底掌握redux-thunk源碼,從而對redux有更深入的了解和應用。正文在解讀Redux-thunk源碼之前我們需要先掌握redux的基本工作機制和中間件實現原理,這樣才能更好地理解源碼背後的奧義。
  • Exodus Redux KODI電影插件3月推薦
    14.進入repo後,找到 repository.exodusredux-0.0.8.zip,點擊確定21.安裝需要等待幾分鐘,根據你的網絡決定安裝結束--下面介紹一下插件內容使用方法安裝好後回到主頁,插件選項,進入Exodus Redux
  • Epic周免遊戲1/2《地鐵:最後的曙光重製版(Metro:Last Light Redux)》
    Epic Games商店領取地址:https://www.epicgames.com/store/zh-CN/product/metro-last-light-redux/home(註:可點擊下方閱讀原文直接跳轉到領取頁面)領取時間:2021.02.05-2021.02.11B站視頻:https://www.bilibili.com
  • React 靈魂 23 問,你能答對幾個?
    相關連結:你真的理解setState嗎?:2、聊聊 react@16.4 + 的生命周期相關連接:React 生命周期 我對 React v16.4 生命周期的理解3、useEffect(fn, []) 和 componentDidMount 有什麼差異?
  • 大秦賦:華陽太后一句我特別理解你,趙姬徹底崩潰
    這個時候的嬴政是徹底心死了,自己的生母居然要殺自己。雖然這不是趙姬的本意,回到宮中後嫪毐受到了訓斥。但是嫪毐這個人是不作就不會死的性格,即使自己的醜事暴露,但是依舊我行我素,絲毫沒有收斂的跡象。但是到了宮裡後,趙姬卻出乎意料的沒有同意,直接承認了自己和嫪毐已經生了孩子,這個時候呂不韋也徹底懵了,此時呂不韋明白自己和趙姬的政治聯盟不存在了。呂不韋回到自己的相府左思右想決定還是得殺嫪毐,即使太后不同意,自己也得殺掉,因為嫪毐的行徑已經有謀反的意圖,如果自己不處理,將來自己肯定是逃不了干係的。
  • 徹底理解Python中的yield
    作者|丁彥軍來源|戀習Python(ID:sldata2017)沒有用過的東西,沒有深刻理解的東西很難說自己會
  • 當男生「徹底喜歡」上你,才會有的3表現,臭妹妹別裝不知道!
    當男生「徹底喜歡」上你,才會有的3表現,臭妹妹別裝不知道! 當一個男生開始離不開你,很黏你的時候,你可千萬不要嫌煩,罵他幼稚,這可都是因為他愛你,他想跟你時刻在一起,如果不愛的話,那自然會離你遠遠的。
  • 為什麼他們不能理解我呢?「完全被理解「往往是一種幻想
    他們:哪份工作不累呢(別幻想了)……他們:你這算什麼,我們當年怎麼怎麼樣(你這苦才到哪),那也沒有要辭職啊(你就是太脆弱)。他們:累也沒辦法啊,誰叫你當初不好好學習呢(有因必有果,你現在搞成這樣是你自作自受啊)他們還是沒有理解你。
  • 羽毛球殺球時手腕絕不能下壓,等你明白了,你的殺球就徹底解放了
    羽毛球殺球時手腕絕不能下壓,等你明白了,你的殺球就徹底解放了!如果你能理解,你一定是專業高手,如果你不能理解,請保持克制和忍讓,等你明白了,你就真悟了,你那不給力的殺球就徹底解放了,我不打狂言,此心法送給廣大孜孜不倦地追求重殺的狂人們,如果信我,請你去參悟,如果不信,就請一笑而過,如果你告訴我,你的殺球很重,那我告訴你,如果你按我的方法,你的殺球可以更重(排除原本就以我的方法殺球的朋友)。
  • 如何讓天蠍男徹底愛上你
    和蠍男相處時你要隨時轉換三種角色 一是萌妹子當他需要疼愛的時候 你可以撒嬌賣萌裝可愛 二是老媽子當他需要安慰理解的時候 你要充分表現出對他的包容和理解 三是隱形人當他想自己一個人靜靜的時候 你要乖乖的消失 去做自己的事情 蠍男永遠都不會告訴你一句話
  • 你沒喜歡過 所以理解不了
    我想起幾個月前王俊凱去我想和你唱和三個漂亮女生合唱之後,我氣的關了電視跑上房間打電話給小姨夫哭了一晚上,我覺得太傷心了,自己看著長大的寶貝怎麼會有這麼一天呢?笑著和漂亮的女生唱歌,坦然接受她們的放電,我覺得太生氣了,這個世界上沒有人能和小凱放電的。
  • 盤點《還珠格格》「十大美女」,你還記得有誰嗎?你最喜歡哪一位
    導致代碼難以理解,相關的Bug,問題也帶到了二次開發的框架中。這種強依賴導致的問題會給以後項目升級,遷移帶來很多問題。比如vuex作為Vue的官方推薦的狀態管理方案,只能在Vue的上面使用,不能在陣營上面使用。Redux的狀態管理在陣營上用的多,這個卻能用在Vue之上。
  • 「男生徹底喜歡你的表現.」
    當局者迷這句話從來就是真的,當你被一個男生喜歡的時候,你不僅有可能感覺不到,也根本想像不到他在背後有多少小劇場小心思。想知道男生徹底喜歡上你都有什麼表現嗎?,給他發消息的時候只可能有兩種人,他老闆,或者他徹底喜歡上的女生。
  • 物慾橫流的今天,你是如何理解貧賤夫妻百事哀的?
    現在多數人理解為夫妻之間一旦沒有穩定的經濟基礎,就會感到特別悲哀。我突然對這句話感到莫名的恐懼與無奈,為什麼好好的一句話會被現代人這麼理解,並且樂此不彼的應用,又從不計後果。我們先分開理解夫妻和物質的關係,夫妻是如何結合的?夫妻到底怎樣做才可以算是幸福的結合體?夫妻:丈夫和妻子。
  • 當一個男人,對一個女人,徹底死心是一種什麼感覺
    看到這個邀請問答,非常同情提出問答的男士,非常理解你心如死灰的痛苦,很能理解你在婚姻中承受了非常大的心理壓力,經受了巨大的痛苦,絕望中才在平臺提出這一問答,「徹底死心」是多麼痛苦而絕望之語,有哀莫大於心死的感覺,既然對婚姻中的女人徹底心死就不要再猶豫,離婚。餘生有限,遠離不愛你,讓你徹底死心的女人。
  • 吳京人設徹底崩塌,你還喜歡他嗎?
    打野的硬漢形象也是徹底地紮根在了人們的心底,雖然他不是軍人,但是卻演出了軍魂,但是就在前一陣子,吳京的人設徹底崩塌了,你們知道是咋回事兒嗎?其實,兩個人的描述,幸福是需要雙方共同付出的,他們是獨立的個體,他們也有著自己的感情思想,所以如果遇到了事情是必須互相體諒,互相理解的
  • 什麼是理解?如何提高理解能力?理解記憶法幫你提高思維能力
    一、什麼是理解記憶法理解是什麼?理解就是因每個人的大腦對事物分析決定的一種對事物本質的認識,就是通 常我們所說的知其然,又知其所以然,一般也稱為了解或領會。理解與概念和問題都有密切關係,有時是互相重疊的。