iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 18
0
自我挑戰組

React初心者30天的探索之路系列 第 18

[Day 18] 像是迷霧森林的React Redux

  • 分享至 

  • xImage
  •  

寫過vue就知道有vue有提供vuex來做資料(state)的集中管理,那麼React就是藉由Redux來達成,不過讓我有點訝異的應該是React 跟 Redux沒有關係,我以為Redux和React的關係就像vue和vuex一樣(殊不知完全不是)!

在找資料的過程中比對目前的官網文件,其實看得有點痛苦,一下子import React-Redux,一下子import Redux,這兩個難道是不一樣的東西嗎,花了一點時間才理解,原來React-Redux是React與Redux的橋樑

什麼是Redux?

Redux一個用於應用程式狀態管理的開源JavaScript庫。Redux經常與React搭配運用,但其也可以獨立使用 (來自維基百科的解釋

先來認識四個重要的名詞

  • state: 儲存資料地方
  • action :描述動作(通常是大寫,有點像定義常數那樣,定義這個動作的名稱
  • reducer :根據action定義的動作並實作具體的功能(將原先的state作資料異動
  • dispatch :觸發action的指令,進而觸發Reducer更新資料

首先,先安裝Redux 和 React-Redux

npm install redux react-redux

reducer 會有兩個參數,第一個為初始狀態的state,即initalState,第二個則是傳入action

接下來根據傳入的action的類型,對資料做不同的操作(對當前數字做加減),記得一定要在default回傳原值,才能處理那些沒被定義的action type

const initialState = {
    count: 0
}

export default function reducer(prevState = initialState, action) {
    switch (action.type) {
        case "ADD_ONE":
            return { 
                ...prevState,
                count: prevState.count +1
            }
        case "MINUS_ONE":
            return { 
                ...prevState,
                count: prevState.count -1
            }
        default:
            return prevState;
    }
}

創建完reducer後要在index.js引入createStore ,並且傳入reducer,假設我有多個reducer呢?那就可以引用redux提供的combineReducers方法來整合多個reducer,再一口氣傳入全部reducer

React透過provider接收傳入的store ,可以讓所有的子組件透過props都拿到state,每個專案都應該只有一個store

在index.js建立一個provider,並且包住< App/>

import { createStore } from 'redux';
import { Provider }  from 'react-redux'
import reducer from './redux/reducers';
const store = createStore(reducer);

store.subscribe(()=>{
   console.log(store.getState())
})
  

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

connect的概念是將Redux與UI組件結合,Redux負責資料處理,UI組件只要單純根據輸入的資料做畫面渲染即可,這邊有運用的HOC(High order component)的概念,傳入mapStateToProps、mapDispatchToProps,以及原先寫好的class component(Counters)後,會加上一些方法後回傳一個全新的物件

import { connect } from 'react-redux'
import Counters from './Counters'
import { addOne, minusOne } from './redux/action'

const mapStateToProps = (state) => {
    return {
        count: state.count
    }
}

const mapDispatchToProps = dispatch => {
    return{
        addOne:()=>{
            dispatch(addOne())
        },
        minusOne: () => {
            dispatch(minusOne());
        },
    }
}

const Counter = connect(
    mapStateToProps,
    mapDispatchToProps
)(Counters);

export default Counter

connect 共有4個參數,但我看大部分的情境只會用到前面兩個,所以後面兩個參數就不介紹了

function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)

mapStateToProps

將store的state 對應成props state,日後如果state有更新,那麼mapStateToProps也會跟著改變

mapDispatchToProps

將store的dispatch 對應成為props dispatch,假設connect沒有傳入,預設會帶入dispatch

這是被傳入的Counters component,透過props拿到剛剛connect帶入的mapStateToProps與mapDispatchToProps,此時點擊按鈕就能成功修改遠在天邊的initialState.count

import React, { Component, Fragment } from 'react';


class Counters extends Component {
    render() {
        const { addOne, minusOne, count} = this.props
        return (
            <Fragment>
                <h1>{count}</h1>
                <button onClick={addOne}>+1</button>
                <button onClick={minusOne}>-1</button>
            </Fragment>
        )
    }
}



export default Counters

之前問有學過React的朋友,他們覺得最難理解的是那一個部分?大部分都回Redux,的確是名不虛傳XD


上一篇
[Day 17] React Developer Tools除錯工具
下一篇
[Day 19] Redux Middleware
系列文
React初心者30天的探索之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言