Hello!大家好啊!就算標題讓人搞不清楚狀況,但是點進來的時候應該還沒忘記昨天的成就感吧XD,為了能夠在最後獲得更大的滿足,今天再來開始繼續學習吧!
在介紹Redux
之前我必須先說,他和React
是個完完全全沒有任何關係的套件,也就是說就算沒有Redux
,React
我們一樣也可以寫得很開心,但是相信我,如果有他在的話,開發React
一定會更開心...其實我也不確定XD,但我們一起來見證吧!
Redux
是給JavaScript
管理一些我們已經知道的值,也就是說可以把它當成一個管理資料的容器,並可以讓分散在不同地方的各個組件自由取用,使用Redux
好處和從父組件傳props
到子組件的道理一樣,讓資料擁有一致的特性。
好的,從這裡開始又是一段新的旅程,我們需要花幾跟篇福來說明,因為這有點複雜,所以我會盡量簡單並且由淺入深的解釋,請大家再跟著我一起認識Redux
吧!
雖然時間很短,但還是請大家先忘記之前學的React
,讓我們從一個新專案開始,不曉得各位還記不記得,首先從npm init
開始,相信大家應該都很熟,所以接下來會快速帶過:
npm init -y
建立專案:webpack
:
npm i webpack -dev
npm i webpack-cli -dev
npm i webpack-dev-server -dev
babel
,因為本篇不寫JSX
所以先不下載@babel/preset-react
:
npm i babel-loader -dev
npm i @babel/core -dev
npm i @babel/preset-env
webpack
的設定檔「webpack.config.js」,並設定babel-loader
:
const path = require('path');
module.exports = {
//這個webpack打包的對象
entry: {
index: ['./index.js']
},
output: {
//這裡是打包後的檔案名稱
filename: 'bundle.js',
//打包後的路徑,這裡使用path模組的resolve()取得絕對位置,也就是目前專案的根目錄
path: path.resolve('./'),
},
module:{
rules:[
{test:/\.js$/,use:{loader:'babel-loader',options:{presets:['@babel/preset-env']}}}
]
}
};
redux
:
npm i redux
JavaScript
的「index.js」和唯一的畫面「index.html」,index.html的內容為:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
不是我想要湊字數,是最不能忘記的是記得要import
下載的redux
套件,這裡只需要從redux
匯入createStore
方法就好:
import { createStore } from "redux"
本文開頭有提到說Redux
是用來管理JavaScript
中的資料,所以想當然我們必須要先有個資料物件,就像我們昨天的訊息資料一樣,不過這裡先簡單存個num
:
import { createStore } from "redux"
//一開始拿到的資料
const data = {num : 1}
這裡要設定的動作是異動資料的意思,像是更改資料內容、新增或刪除等等,但是看到這裡也許會覺得很奇怪,因為資料是從server
端撈出來的,所以最源頭的資料應該是不能更改的!
沒錯!這個觀念是正確,不過我們稍後再說,這裡要設定的動作是一個建構器,他會產生一個物件,裡面存有兩個屬性,第一個type
代表動作的指令,第二個payload
則是執行的動作要傳入的資料,而這裡payload
指定的值我們會藉由呼叫addNum
的時候指定:
import { createStore } from "redux"
const data = {num : 1}
//動作指令設定
const addNum = article => ({ type: "addNum", payload: article })
這邊就是精髓了,整個晚上幾乎都卡在這裡,所以我不會讓各位和我一樣的,一起搭上飛機吧!
有了資料和動作後,我們要試著把他們綁再一起,這時候會用一個匿名函式去處理它,在redux
中稱它為Reducer
,我們會在裡面描述每個動作對資料發生的事情,而因為要執行的動作通常不只一個,所以會用switch
來判斷目前收到的指令(就是剛剛設定的type
)為哪個動作:
import { createStore } from "redux"
const data = {num : 1}
const addNum = article => ({ type: "addNum", payload: article })
/*將一開始拿到的資料指定給第一個參數state,第二個參數action會在執行動作時傳入當初設定的指令物件,例如執行addNum時會將整個物件丟給action*/
const rootReducer = (state = data, action) => {
//用switch.type來判斷指令為何
switch (action.type) {
case "addNum":
/*如果是addNum的話就把初始數字加上payload的值,並回傳
**注意這裡只做回傳,並不對原資料做異動*/
return {num: state.num + action.payload }
default:
//沒有符合執行動作的條件就不做處理直接回傳
return state
}
}
Reducer
放進store
中這個store
就是從一開始一直在說的,他會保管一個應用程式中所有的資料,所以我們把剛剛設定的Reducer
用createStore
交給他吧!
import { createStore } from "redux"
const addNum = article => ({ type: "addNum", payload: article })
const data = {num : 1}
const rootReducer = (state = data, action) => {
switch (action.type) {
case "addNum":
return {num: state.num + action.payload }
default:
return state
}
}
//託付剛剛的一番辛苦完成的Reducer
const store = createStore(rootReducer)
在這裡因為我們只是單純用redux而已,所以也沒辦法用什麼組件去觸發剛剛做的store
,不過別擔心,在這個階段就先把剛剛宣告的addNum
動作和保管著資料的store
加入全域中,讓我們可以直接在console
中執行:
import { createStore } from "redux"
const addNum = article => ({ type: "addNum", payload: article })
const data = {num : 1}
const rootReducer = (state = data, action) => {
switch (action.type) {
case "addNum":
return {num: state.num + action.payload }
default:
return state
}
}
const store = createStore(rootReducer)
//這邊多加了一個data是想讓大家確認原本的資料是不會變的!
window.data = data;
window.store = store;
window.addNum = addNum;
在全域中設定完後就可以用webpack -p
打包index.js
檔了,打包完後不論是直接打開index.html
或是用webpack-dev-server
都可以,開啟後就可以進行測試。
.getState()
這個函式可以看到目前store()
所保管的資料內容:
.subscribe()
這個函式是store
的監聽器,他會需要一個function
當引數,用來在store
保管的資料發生改變的時候執行,以下我們先設定監聽:
.dispatch()
這裡我們就來傳入剛剛設定的方法吧!另外記得我們在設定addNum
的時候為他留了一個參數嗎?現在也不要忘了指定他,不然payload
就會是undefined
了:
登愣!看到這一刻真的會有感動的感覺,當我執行動作時他給了我兩個回應,第一個是我們剛剛用.subscribe()
設定的監聽器,沒錯!資料被改變了!而第二個就是透過addNum
建構出來的物件,這個不重要,重要的是我們再一次執行store.getState()
來確認被保管的資料如何了:
果然華麗的加上2了!最後再來確認原本的資料是不是還是最初的樣子:
這是本篇的GitHub程式碼:
GitHub連結
是不是覺得這一切有點棒!雖然目前做到的事情感覺不多,但至少我們已經瞭解了在redux
中他是透過Reducer
來設定事件的觸發、store
來保管資料,且可以利用.getState()
隨時確認資料內容、並在使用.dispatch()
發生改變的時候透過.subscribe()
監聽並執行指定的事件,當我們對redux
有了初步的認識後,明天就能夠試著把他加入react
中!請各位敬請期待!包括我也很期待XD
最後感謝各位大大的觀看,畢竟小弟也是第一次學習,所以不論文章中有任何錯誤或是解釋不清楚的地方,還麻煩各位大大留言告訴我,我會在盡快補充或修正文章內容的!謝謝大家
參考文章:
大大,您的意思是React 和 Redux 的關係,對開發者來說,類似蛋和蔥花嗎XD
蔥花蛋比蛋好吃啊~
沒錯!
如果網頁是薯條,React
就像番茄醬、Redux
就像糖包,雖然薯條加番茄醬就不錯了,但是再加糖包的隱藏吃法更讚XD
麥當勞
好餓
噓!不能業配啦