React-Redux基礎(二):React 裏面如何使用 Redux,Redux 修改操作

上篇博客,我們說了原生 redux 的用法,這一篇我們就來說說如何和 react 來配合,因爲 redux 這個東西儘管能單用,但是很少這麼做。

首先第一件事,安裝:npm install redux react-redux -D

redux 是這個東西的本體,核心,沒有它就用不了。

react-redux 它則是一個橋樑,它讓我們的 react 可以使用 redux。

在用之前,我們需要先認識三個主要的組件:

1,Provider,翻譯過來是提供者。它是一個包裹,它負責包裹住我們的整個程序

因爲我們的 redux 是希望能夠在整個程序之內來共享數據的,所以你就得把整個程序全都交給它來處理,那麼它就需要在所有的程序之外。它有點像我們前面說過的 Router,Router 它也是包在最外面的。

2,connect,因爲實際上來說,它是在最外面沒錯,你整個程序都在它裏面,都歸他管。但是如果你自己一級一級往上找,去找到它,然後在去拿數據,這個也是及其費勁的。所以這個 connect 它是起到一個連接的作用。

那這個連接是幹什麼的呢?它可以幫助我們的模塊來訪問 redux。

3,reducer,我們在這篇博客裏面,會看到 reducer 怎麼樣能夠跟我們的組件配合起來。

 

首先,我們將上節課原生的代碼刪了,因爲我們不會在單用 redux 了。將代碼恢復到之前的狀態:

接下來第一件事就來了,我們需要把整個程序給包住。那麼最簡單的方法莫過於放到 index.js 裏面,因爲 App 就在這裏。

首先,我們需要先引幾個東西:

我們需要先把 createStore 給引進來,因爲 redux 必須得創建一個 store,才能開始用。

注意,createStore 它是 redux 所提供的功能。而 Provider 和 connect,它們不是 redux 的功能,是 react-redux 的功能。

所以我們在引入的時候,注意不要將 redux 和 react-redux 裏面的東西搞混了。

簡單來說下是爲什麼:因爲 redux,它只提供存儲。它自己什麼也沒有,上一篇博客我們也見識過了。

react-redux 它是一個橋樑,它幫助我們來跟 redux 做整合,所以 Provider 和 connect 都是它來提供的,因爲是它來幫助我們的組件來訪問 redux 的。

接下來,先不忙着包裹,我們先創建一個 store:

到目前爲止,和以前 redux 單用的寫法是沒區別的。那麼接下來怎麼去把它包起來呢?

這個 Provider 它在最外層,把我們整個程序全都包住。這裏稍微提下,Provider 和 Router 是會有衝突的,這個後面會細講,這裏大家先有個印象。

爲什麼這裏要給它傳一個 store 對象的參數呢?

因爲說白了,你在這光是 create 一個 store 是沒有辦法起作用的,別人不會自動去找這個程序裏面,所有帶 store 的變量在哪,得你主動把 store 給 Provider 傳過去,意思就是告訴它,這個程序所有的數據都歸它管。

那麼準備工作做好了,那在組件裏面怎麼用呢?

首先,我們第一件事是需要先把這個組件,給它 connect 連接到整個 redux 上面去。

怎麼做呢?第一步,我們先引入 connect:

這裏注意別引錯了,它在 react-redux 裏面,而不是 redux 上。

然後有 connect 之後,它怎麼用呢?它的用法略微有點奇怪,不是放在 class 裏面,而是放在外面的。

我們在 export default 的時候,需要用 connect 來把 App 給包裹住

這裏是執行兩次,所以會有 2 對小括號。

執行第一次的時候,它裏面有一些參數。然後執行第二次的時候,纔是我們具體要包裹的元素。

那麼第一次執行的參數又有什麼呢?

它的參數有 2 個第 1 個是個函數,第 2 個是個 json: 

函數我們又可以寫成箭頭函數,所以如下圖:

這裏簡單來解釋下 connect 它這 2 個參數都有什麼用處。

首先第一個函數,它是專門用來合併東西的。合併什麼呢?

我們要明白,所有來自 redux 的數據,不會直接成爲你的 state,你的 state 還是你的 state。(這裏說的 state 是組件內的 this.state)

實際上在 redux 官方里面,它是推薦你:如果一些數據只是在我這個組件之內用,那你就不要往 redux 身上扔。

因爲 redux 裏面越乾淨,越少越好。所以你的 state 還是你的 state,我們不碰它。(這裏說的 state 是組件內的 this.state)

那這個時候,它帶過來的數據放哪呢?它是放在你的 props 身上。換句話說,它給你加了個 props。

所以,這個函數具體來說,它會給你 2 個東西。

第一,它會給你一個 state,這個 state 是它的 state,也就是我們傳到 reducer 裏面的那個初始數據

然後接下來,這個 props 是你的,就是你在組件內使用的 this.props

所以,這個函數內的第一個參數 state,是來自於 redux 裏面的全局數據 state。

而第二個參數 props,來自於我們自身的 this.props,就是將來誰去用你這個組件,它傳給你的參數。

而我們要做的就是把它們兩個合併起來。因爲它們可能會衝突,畢竟它們都是體現在 this.props 身上的。

 

爲什麼要把它們兩個要合併呢?

比如現在 state 裏面有個 name,然後 App 組件上面,它自己也有個 name:

如果不衝突一切都好辦,那這時候就出現問題了,就衝突了:全局數據的 state 裏面有 name,組件自身也有 name。

那我應該聽誰的?還是說改個名什麼的?我們可以先把它們打印出來看看:

所以這個時候就需要我們自己來合併了。

然後合併的時候,我們希望以 state 爲主,換句話來說,就是我希望更多的來使用 redux 裏面的東西。

那麼,我們可以使用 Object.assign 這個方法來進行合併:

看到這裏,你可能會很奇怪,上面你不是說以 state 爲主嗎,那爲什麼這裏把 state 放後面?

實際上來說是這樣的,因爲我把 state 放後面,那 state 裏面的東西就會覆蓋到 props 裏面去。

換句話說,如果同樣有 name,那我用的就是 state 裏面的 name。因爲它是覆蓋別人的一方。

 

接下來,我們這麼做是有 2 個小問題的:

第一,我們可以簡化。因爲它這個函數就只是返回這一個東西,所以可以直接這麼寫:

第二,直接覆蓋是有問題的。其實說白了就一件事,props 不能覆蓋。我們在前面的 React 基礎裏面就說過,props 是隻讀的

所以我們可以在前面加上一個空對象:

這個意思就是說,先把 props 裏面所有的東西,全部複製到這個空 json 裏面去。

然後再把 state 裏面的東西全覆蓋到 json 裏面去。

這樣的話,萬一 state 和 props 有衝突,也是以 state 的爲準,因爲它是後進去的。

 

然後這時候,我們希望把名字和年齡給打印出來,怎麼做呢?

其實 redux 它裏面的數據,也就是 state 裏面所有的東西,最終都會進到 props 裏面去。

所以我們可以用 this.props.xxx 來找相應的東西:

可以看到,就是這麼簡單。

 

對於初學者,這裏比較容易混淆。那麼,我們再來回憶一下。

首先,我們這個 redux,它裏面的數據 state,會自動的進入到我們組件裏的 props 裏面,而不是我們組件裏面的對象 this.state

比如,我們可以把自己的 state 初始化一個 a 屬性。然後在 render 裏面打印下我的 state,以及我的 props:

可以看到,我們自己的 state 裏面,就一個 a: 0。

所以 redux 不會把它裏面的數據放到你的 state 裏面去,它只會放到你的 props 身上。

因爲 props 是不可修改,只讀的,並且結合我們前面說過的,redux 它本身就是一個單向的。

它不太希望你直接去給我 redux 的 state 賦值,因爲你這樣做會破壞我的單向數據傳遞。所以在這個時候,它就把數據直接放到 props 裏面。

其實,這樣做,即是方便了我們用,也能夠不干擾我們自己組件的局部狀態 this.state,同時也能夠防止我們對它直接賦值。

所以一舉三得,這個就是 redux 最基本的使用。

 

然後,我們前面說過,redux 是在整個程序之內,去共享數據的。

換句話說,我現在只有一個組件,其實是看不出來 redux 優勢的。

那麼我們就再來一個組件 Cmp1.js:

然後在 App.js 裏面引入:

可以看到數據是沒問題的。

那麼我們真正想做的是,能夠在 Cpm1 組件裏面放一個按鈕,然後點擊的時候,可以給 age 加個3:

那麼具體怎麼做呢?這時候我們就需要 connect 的第二個參數了。這個參數,是用來封裝 action 的。

我們在上一篇博客裏面說過,你可以通過 dispatch 來做,但是這樣略微有一點麻煩。

所以我們的 react-redux,它可以幫助我們來封裝我們的這個 action。

簡單來說,我們直接在裏面寫方法就行。比如,我們就叫 addAge:

addAge 這個名字叫啥都行,因爲這個不是全局的,它只是在你這個組件之內來用的,所以你不用擔心。

然後我們可以給這個 addAge 傳個參數,傳什麼都行,隨便你。因爲這是你自己的方法。比如我們傳個 n:

然後接下來,我們就可以來調用它:

那麼 addAge 它裏面具體需要做什麼呢?

如果說它裏面還要繼續寫 this.store.dispatch,那我們封裝它就沒有意義了,還不如我們直接拿到上面的 fn 裏面去寫,看着也方便。

所以這個 addAge 它裏面極度的簡化,我們自己不需要去 dispatch,它替我們都封裝好了。

所以你只要 return 一個需要提交的 action 對象就行了,其餘的工作它替你搞定。(前面我們有說過 action 就是一個 json,所以這裏直接 return 一個空對象就行)

所以這裏的意思就是:你就告訴我,你的 action 是什麼,其他的我來。

然後 action 裏面需要 2 個東西:

第一個是 type,這個是必須的,並且兩邊也必須得一樣。

第二個 n,就是對應的參數。

這裏和我們上一篇博客裏面講的 action 其實是一樣的。

所以 connect 裏面的這個操作,它幫助你簡化了,你自己不需要去 dispatch,它替你封裝好了,你只需要給它返回一個需要提交的 action 對象就好了。

那如果我還想再來一個組件 Cmp2,改姓名:

和上面一樣,需要注意的就是 type: 'setname',必須得和 index.js 裏面的 reducer 裏面的 setname 一致:

然後在 App.js 裏面引入:

所以,我們就簡單的講解了:

1,react 裏面如何使用 redux。

2,redux 它裏面的東西,要如何修改。

那麼到此,這個東西就已經完成了。

 

其實我們現在這個東西還算不上完美,因爲它裏面還有很多問題:

比如現在,我們在 index.js 裏面用的是一個單一的 reducer。

你想象一下,整個項目當中,所有的數據全在這一個函數裏面,就問你怕不怕。

因爲如果說真的把所有的數據全扔到這一個函數裏面,那整個程序的數據太多了,這個函數會寫死人的,負責維護這個函數的人辭職率會賊高。

所以我們要想辦法怎麼樣把它做成多套東西,也就是把它拆成模塊。比如這個是用戶數據,那個是它的購物車數據,等等。

所以我們要考慮的第一個問題就是:如何不要這種單一數據對象,而是多個聯合的數據對象,這個會更好一點。

 

第二個問題就是,在程序裏面,但凡是改了某一個東西,就順便還需要更改別的地方。這種情況,都是不應該發生的。

實際上來說,如果我在將來因爲項目規範,又或者覺得名字不好聽,等各種原因,把 setname 改成了 set_name:

那麼實際上,所有用到你這個 setname 的地方,就都得改。

如果項目小,想一下還能記起來哪些地方要改。但是對於一個大型的項目來說,靠記憶,你覺得靠譜嗎?如果負責這個模塊的同事離職了,下一位接盤的估計得哭死。

所以說,我們還有另一個問題,就是這個 action,它是一個字符串。那怎麼樣才能把它提取出來,讓它是一個比較容易修改的狀態,這就是我們需要解決的問題。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章