Redux 入門

學習 Redux 是個十分痛苦的過程齐媒,因為你有可能不知道 Redux 和 React-Redux 是兩個不同的東西况木,而且一堆看起來很新的概念總能把新手繞暈忌卤。

這篇文章將從一個簡單的例子開始講 Redux 到底要怎么使用像啼。建議先學習 EventHub 或者看我的另一篇文章 React 的兄弟組件通信啊胶,因為 Redux 的主要思想就是 EventHub 思想。

純 JS + Redux

先說下需求慌随,首先要有一個數(shù)字芬沉,點擊按鈕數(shù)字加1,沒了阁猜。不過這個過程要使用到 Redux丸逸,也就是說這個數(shù)字要放在全局變量中。

這里就用一個簡單的 index.html 寫就完了剃袍。HTML 代碼如下:

<div id="app"></div>

接下來寫 JS黄刚。

function add() {
    store.dispatch({ type: 'add', payload: 1 }) // 1. dispatch 一個 action
}

function render() {
    let app = document.querySelector('#app')
    app.innerHTML = `
    Clicked: <span id="value">${store.getState()}</span> times
    <div>
        <button id="add" onclick="add1()">+1</button>
    </div> `
}

function stateChanger(state, action) {
    if (state === undefined) {
       return 0
    }
    else {
        if (action.type === 'add') {
            let newState = state + action.payload
            return newState // 2. 根據(jù)操作生成新的 state 觸發(fā)一個事件
        }
    }
}

let store = Redux.createStore(stateChanger)

render(store)
store.subscribe(render) // 3. 接收到事件,重新 render

這里說明一下運行的步驟:

  1. 首先運行 render() 將標簽都 append 到 document 上民效,并在按鈕上綁定 add 回調(diào)
  2. 點擊了按鈕執(zhí)行 add() 憔维,然后 dispatch 一個 action(相當于觸發(fā)了名為“add”的一個事件)
  3. 因為在 Redux.createStore(stateChanger) 時,Redux 會監(jiān)聽 action(也就是事件)的觸發(fā)畏邢,所以會執(zhí)行 stateChanger 里的代碼
  4. 因為在 store.subscribe(render) 在 if-else 里修改了新的 state 后业扒,Redux 會重新執(zhí)行 render() 函數(shù),從而更新整個頁面

Redux 的用法就是這么簡單舒萎!但是為什么我們看官方檔看得想死呢程储?因為加了 React,后來的所有看起來很變態(tài)的使用方法都是為了解決:怎么讓代碼更好分離臂寝,怎么獲取全局變量等章鲤。思想還是那個思想。

React + Redux

現(xiàn)在我們正式加入 React咆贬,使用官方提供的create-react-app來創(chuàng)建應用败徊。App 組件寫成這樣:

// App.js
class App extends Component {
    add1() {
        this.props.store.dispatch({  // 1. dispatch 一個 action
            type: 'add',
            payload: 1
        })
    }
    render() {
        return (
            <div className="App">
                Clicked: <span id="value">{this.props.value}</span> times
                <div>
                    <button id="add1" onClick={this.add1.bind(this)}>+1</button>
                </div>
            </div>
        )
    }
}

export default App

在入口文件去初始化 Redux:

const stateChanger = (state, action) => {
    if (state === undefined) {
        return 0
    }
    else {
        if (action.type === 'add') {
            let newState = state + action.payload
            return newState // 2. 根據(jù)操作生成新的 state 觸發(fā)一個事件
        }
        else {
            return state
        }
    }
}

function render() {
    ReactDOM.render(
        <App
            value={store.getState()}
            store={store}
        />,
        document.getElementById('root')
    )
}

const store = createStore(stateChanger)

store.subscribe(render) // 3. 接收到事件,重新 render

render()

感覺好像沒什么變化呀素征,不就將一個 index.html 分成了 index.js 和 App.js 么集嵌?但是這里涉及到怎么去獲取 store 的問題萝挤。

如果一兩個組件就用 props 來傳 store 就好了,但是如果組件很深根欧,那么 store 就要像傳家保一樣一層層往下傳怜珍,十分麻煩。

為了解決這個問題凤粗, React 社區(qū)又推出了一個新的工具:React-Redux酥泛。注意這個和 Redux 沒有太大關(guān)系。為了說明這兩個是不一樣嫌拣,我放下他們的官網(wǎng):Redux 官網(wǎng)柔袁,React-Redux 官網(wǎng)

React + Redux + React-Redux

先說明這個工具就只是用來讓別的組件可以訪問到 store 而已异逐,所以它只有 4 個API捶索,其中主要我們要用的就 2 個:Provider, connect。簡單理解:

  1. Provider:將 store 放在頂層組件
  2. connect:將 store 里的數(shù)據(jù)和 dispatch action (也就是觸發(fā)事件)和當前組件綁定灰瞻,使得該組件可以自由訪問和修改 store

現(xiàn)在修改上面兩個文件:

// index.js
const stateChanger = (state, action) => {
    if (state === undefined) {
        return { n: 0 }
    }
    else {
        if (action.type === 'add') {
            let newState =  {
                n: state.n + action.payload
            }
            return newState
        }
        else {
            return state
        }
    }
}

const store = createStore(stateChanger)

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root')
)

下面的 App.js

class App extends Component {
    render() {
        return (
            <div className="App">
                Clicked: <span id="value">{this.props.n}</span> times
                <div>
                    <button id="add" onClick={this.props.add.bind(this)}>+1</button>
                </div>
            </div>
        )
    }
}

// 將部分 store 里的 state 映射到 props 上
function mapStateToProps(state) {
    return {
        n: state.n
    }
}

// 將 dispatch action 相關(guān)操作映射到 props 上
function mapDispatchToProps(dispatch) {
    return {
        add: () => {
            dispatch({ type: 'add', payload: 1 })
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

來對比一下兩份代碼:

少了哪些腥例?

  1. 不用 store.subscribe(render),Provider 會在更新值后自動重新渲染
  2. 不用在組件 App 里寫回調(diào)函數(shù)了酝润,在 mapDispatchToProps 里聲明事件燎竖,這個事件會就負責調(diào)用 dispatch(action)

多了哪些?

  1. 要在 App 組件外再去套一層 <Provider/>
  2. 將 App 組件和 state要销,調(diào)用 dispatch 的函數(shù)連接起來构回。連接(映射)后的結(jié)果是,所有 state 數(shù)據(jù)和調(diào)用 dispatch 的函數(shù)都可以從 this.props 得到

這樣就解決了組件訪問疏咐,修改 store 里的 state 問題纤掸。唉,繞了一大圈就為了搞這些事凳鬓。

那些變態(tài)概念

Redux 為什么這么難茁肠,是因為它將很簡單的概念給了個新名字罷了。

Redux

  1. Store:存放全局數(shù)據(jù)的一個東西缩举,但是要通過 store.getState() 來獲取全局數(shù)據(jù)
  2. State:全局數(shù)據(jù)
  3. Action:對應 EventHub 里的事件,actionType 就是事件名匹颤,payload 就是傳入的數(shù)據(jù)
  4. Dispatch:觸發(fā)事件仅孩,如 dispatch({ type: 'add', payload: 1}),就是指觸發(fā)一個名為“add”的事件印蓖,并帶上了數(shù)據(jù) 1
  5. Reducers:對應觸發(fā)事件后的回調(diào)函數(shù)辽慕,如我們平時聽到的onError = xxx,這個 xxx 就是 Reducer赦肃,這個例子的 Reducer 就是 stateChanger

React-Redux

  1. Provider:可以看成一個包住最外面 App 的一個標簽溅蛉,這個標簽傳入 store 后公浪,通過某些方法所有組件都可以訪問到 store
  2. mapStateToProps:將存在 store 里的數(shù)據(jù)放在這個組件的 props 上
  3. mapDispatchToProps:將需要調(diào)用 dispatch 的函數(shù)放在這個組件的 props 上
  4. connect:將上面兩個東西和這組件聯(lián)系起來

是不是很煩,嗯船侧,我也是這么覺得的欠气,明明很簡單的概念,就是不好好說話镜撩。
(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末预柒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袁梗,更是在濱河造成了極大的恐慌宜鸯,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遮怜,死亡現(xiàn)場離奇詭異淋袖,居然都是意外死亡,警方通過查閱死者的電腦和手機锯梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門即碗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人涝桅,你說我怎么就攤上這事拜姿。” “怎么了冯遂?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵蕊肥,是天一觀的道長。 經(jīng)常有香客問我蛤肌,道長壁却,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任裸准,我火速辦了婚禮展东,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘炒俱。我一直安慰自己盐肃,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布权悟。 她就那樣靜靜地躺著砸王,像睡著了一般。 火紅的嫁衣襯著肌膚如雪峦阁。 梳的紋絲不亂的頭發(fā)上谦铃,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音榔昔,去河邊找鬼驹闰。 笑死瘪菌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的嘹朗。 我是一名探鬼主播师妙,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骡显!你這毒婦竟也來了疆栏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惫谤,失蹤者是張志新(化名)和其女友劉穎壁顶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溜歪,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡若专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝴猪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调衰。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖自阱,靈堂內(nèi)的尸體忽然破棺而出嚎莉,到底是詐尸還是另有隱情,我是刑警寧澤沛豌,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布趋箩,位于F島的核電站,受9級特大地震影響加派,放射性物質(zhì)發(fā)生泄漏叫确。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一芍锦、第九天 我趴在偏房一處隱蔽的房頂上張望竹勉。 院中可真熱鬧,春花似錦娄琉、人聲如沸次乓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽檬输。三九已至,卻和暖如春匈棘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背析命。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工主卫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留逃默,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓簇搅,卻偏偏與公主長得像完域,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瘩将,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容