本文主要記錄下本身在react道路上的爬坑過程 以及對於剛學習redux的同窗提供一些可供參考的例子。vue
以前用vue用了好久 vue的語法糖用起來是真的舒服 不過如今公司項目用的是react 只好默默的從vue轉到react 其實畢竟他們都是相似的框架, 雖然語法大不一樣, 可是有些地方的思想仍是很像的, 廢話很少說了,開始正文...
本文主要分爲兩個部分:redux和react-redux。 首先大概過一下redux的基礎部分:react
要知道redux和react並無半毛錢的關係,redux甚至能夠和jq一塊兒用。 react-redux纔是react的用於便捷操做redux的第三方插件。因此呢,學習react-redux以前咱們要比較熟悉的瞭解redux的思想。本文比較直接,不來虛的,直接上代碼:
首先就很熟悉了
1 使用官方腳手架create-react-app redux-demo
npm
2 環境搭建好以後 繼續安裝reduxnpm install redux --S
redux
進入到項目文件夾 把咱們用不到的全咔咔刪掉瀏覽器
在src/index.js裏引入redux並建立action reducer和store
src/index.js:app
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; import { createStore } from 'redux' //這是redux的原始state const tiger = 10000 //這是action const increase = { type:'漲工資' } const decrease = { type:'扣工資' } //這是reducer const reducer = (state = tiger, action) => { switch (action.type){ case '漲工資': return state += 100; case '扣工資': return state -= 100; default: return state; } } //建立store const store = createStore(reducer); console.log(store.getState()) ReactDOM.render(<App />, document.getElementById('root')); registerServiceWorker();
這裏大概解釋下每一個的意思:
action:行爲 它是一個對象 裏面必有type來指定其類型 這個類型能夠理解爲你要作什麼,reducer要根據action的type來返回不一樣的state 每一個項目有且能夠有多個action
reducer: 能夠理解爲一個專門處理state的工廠 給他一箇舊數據它會根據不一樣action.type返回新的數據 也就是:舊state + action = 新state 每一個項目有且能夠有多個reducer
store: store本質上是一個狀態樹,保存了全部對象的狀態。任何UI組件都能直接的從store訪問特定對象的狀態。每一個項目有且只能有一個store
腦子裏有了這些基本的概念後咱們就能夠把reducer放到createStore裏並建立好store了框架
能夠看到 代碼的最後咱們打印了store.getState() 這段代碼簡單理解就是打印下store裏的數據
由於咱們只是寫了action並無給它dispatch 因此reducer只會走默認的default 因此僅僅是返回state=tiger 那麼tiger就是咱們以前定義好的state
此時咱們npm start 在瀏覽器打開該demo f12打開控制檯 能夠看到打印的數據爲:10000
這裏咱們只是簡單的回顧下redux的基礎知識 並無在app.js裏面寫任何東西dom
好 能夠看到在上面咱們雖然定義了action 可是好像並無什麼用啊? 接下來咱們要作的事情就是讓它變化了。
剛纔僅僅是得到到初始的數據 這並非咱們想要的結果 在實際項目中咱們確定有不少的需求 不一樣需求對應不一樣功能 不一樣功能得到不一樣數據,因此接下來咱們要用到dispatch給它派發不一樣的action,上代碼:
src/index.js:ide
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; import { createStore } from 'redux' const tiger = 10000 //這是action const increase = { type:'漲工資' } const decrease = { type:'扣工資' } //這是reducer const reducer = (state = tiger, action) => { switch (action.type){ case '漲工資': return state += 100; case '扣工資': return state -= 100; default: return state; } } //建立store const store = createStore(reducer); //訂閱事件 store.subscribe(() => console.log(store.getState()) ); //派發事件 store.dispatch(increase) ReactDOM.render(<App />, document.getElementById('root')); registerServiceWorker();
能夠看到, 打印的數據變成了 11000 也就是說reducer根據dispatch派發的action的type,return了新的state。固然咱們也能夠派發store.dispatch(decrease) 那打印的結果就是 10000,緣由想必你們都知道。
其實咱們僅僅是多寫了store.dispatch(increase) 和 store.subscribe(() =>{}) 他們的每一個做用大概解釋下:
dispatch的做用就是告訴reducer 我給你action, 你要根據個人action.type返回新的state。 而後reducer就會根據action的type,返回新的state。
咱們給它dispatch了action,reducer也作出相應 最後也返回新的state 可是其實這時候console.log()不會打印新的數據 由於state雖然變化了 可是仍是打印store.getState()仍是原始的數據
這時候咱們就須要store.subscribe(() =>{})了 它的做用就是每當reducer返回新的數據 它就會自動更新頁面 把UI組件的state更新下 否則的話 雖然state變化了 頁面仍不會更新(雖然如今尚未其餘組件)學習
好了, 這些就是基本的redux的知識。咱們不難發現,這樣其實挺麻煩的。你須要寫好多好多東西,並且咱們並無把reducer,action什麼的給分離出去,否則的話我還要往不少組件裏面傳不少東西。這對咱們實際開發是很不友好的。
因此, 這時候就十分迫切須要react-redux了。它的做用是幫助咱們操做redux。有了它咱們能夠很方便的寫redux。接下來上代碼:
首先安裝react-redux:
`npm install react-redux --S`
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import { createStore } from 'redux'; import { Provider, connect } from 'react-redux'; class App extends Component { render() { const { PayIncrease, PayDecrease } = this.props; return ( <div className="App"> <div className="App"> <h2>當月工資爲{this.props.tiger}</h2> <button onClick={PayIncrease}>升職加薪</button> <button onClick={PayDecrease}>遲到罰款</button> </div> </div> ); } } const tiger = 10000 //這是action const increase = { type: '漲工資' } const decrease = { type: '扣工資' } //這是reducer const reducer = (state = tiger, action) => { switch (action.type) { case '漲工資': return state += 100; case '扣工資': return state -= 100; default: return state; } } //建立store const store = createStore(reducer); //須要渲染什麼數據 function mapStateToProps(state) { return { tiger: state } } //須要觸發什麼行爲 function mapDispatchToProps(dispatch) { return { PayIncrease: () => dispatch({ type: '漲工資' }), PayDecrease: () => dispatch({ type: '扣工資' }) } } //鏈接組件 App = connect(mapStateToProps, mapDispatchToProps)(App) ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
咱們能夠看到,咱們僅僅對代碼進行了稍微的改造,在index.js裏面寫個APP組件以方便咱們觀察,APP組件裏面的button分別觸發不一樣的事件。
action啊 reducer啊 store啊 想必你們都已經瞭解過了 這裏再也不作過多介紹。咱們主要關注下哪裏有變化:
首先最明顯的是demo中引入react-redux的Provider和connect,它們很是重要!這裏先大概解釋下它們的做用:
Provider:它是react-redux 提供的一個 React 組件,做用是把state傳給它的全部子組件,也就是說 當你用Provider傳入數據後 ,下面的全部子組件均可以共享數據,十分的方便。
Provider的使用方法是:把Provider組件包裹在最外層的組件,如代碼所示,把整個APP組件給包裹住,而後在Provider裏面把store傳過去。注意:必定是在Provider中傳store,不能在APP組件中傳store。
connect:它是一個高階組件 所謂高階組件就是你給它傳入一個組件,它會給你返回新的加工後的組件,注重用法倒簡單,深究其原理就有點難度。這裏不作connect的深究,主要是學會它的用法,畢竟想要深究必須先會使用它。首先它有四個參數([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]),後面兩個參數能夠不寫,不寫的話它是有默認值的。咱們主要關注下前兩個參數mapStateToProps和mapDispatchToProps。
connect的使用方法是:把指定的state和指定的action與React組件鏈接起來,後面括號裏面寫UI組件名。
除此以外demo中還多出了mapStateToProps mapDispatchToProps 他們又有什麼做用呢?通俗一點講的話就是:
好比你在一個很深的UI組件裏 當你想要得到store的數據就很麻煩。mapStateToProps就是告訴store你須要哪一個state,須要什麼數據就直接在mapStateToProps中寫出來,而後store就會返回給你。同理,若是你想要dispatch派發一些行爲怎麼辦呢,mapDispatchToProps就是告訴store你要派發什麼行爲,須要派發什麼行爲就在mapDispatchToProps中寫出來,而後store就會把你想要派發的行爲告訴reducer,接下來你們都應該知道了 reducer就會根據舊的state和action返回新的state。
好了 , 這時候咱們npm start 打開瀏覽器看一下有什麼效果:
能夠看到頁面上已經有內容,多了一段文字和兩個按鈕,當咱們點擊會有什麼反應呢?
果不其然,當咱們點擊'升職加薪'按鈕時候 '當月工資'也相應的增長了。咱們捋一下整個事件流程:
1 點擊按鈕 2 觸發PayDecrease()方法 3 該方法派發相應action 4 reducer根據action的type響應獲得新的state 5 經過{this.props.tiger}拿到新的state 渲染到頁面
ok, 這個簡單的demo咱們就實現了。可是如今還有一個問題:咱們把全部的action reducer store Provider connect等等都寫在了一個頁面,這在咱們實際開發中確定是不合理的,因此,咱們最後就給這個小demo再優化下:
首先,咱們要把action,reducer什麼的抽離出去,做爲一個單獨的文件,而後再導出:
src/index.reducer.js:
const tiger = 10000 //這是action const increase = { type: '漲工資' } const decrease = { type: '扣工資' } //這是reducer const reducer = (state = tiger, action) => { switch (action.type) { case '漲工資': return state += 100; case '扣工資': return state -= 100; default: return state; } } export default reducer
其次,咱們也要把APP組件寫在外面 (此處必定要注意: 導出的不是APP組件,而是connect後的APP組件)
src/APP.js:
import React, { Component } from 'react'; import { connect } from 'react-redux'; class App extends Component { componentDidMount() { console.log(this.props) } render() { const { PayIncrease, PayDecrease } = this.props; return ( <div className="App"> <h2>當月工資爲{this.props.tiger}</h2> <button onClick={PayIncrease}>升職加薪</button> <button onClick={PayDecrease}>遲到罰款</button> </div> ); } } //須要渲染什麼數據 function mapStateToProps(state) { return { tiger: state } } //須要觸發什麼行爲 function mapDispatchToProps(dispatch) { return { PayIncrease: () => dispatch({ type: '漲工資' }), PayDecrease: () => dispatch({ type: '扣工資' }) } } export default App = connect(mapStateToProps, mapDispatchToProps)(App)
把這些東西分離出去以後,此時的index.js看起來明顯就簡潔了許多:
src/index.js:
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import { createStore } from 'redux' import { Provider } from 'react-redux' import reducer from './index.reducer' //建立store const store = createStore(reducer); ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root'));
好了,比較基礎的redux和react-redux例子到這就結束了,感受廢話有點多了。。能看完的都是真愛。。 哪有錯誤 歡迎指正!