iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 14
2
Modern Web

一步一腳印的React旅程系列 第 14

[筆記][React]當React遇上Redux(2)-資料的傳遞方式

Hello!大家好!昨天初步認識了Redux後(真的非常初步XD),知道他如何管理資料了,那今天要來說說在Redux手上的資料該怎麼傳給React的組件!就請各位繼續看下去吧!


事前準備:

上一篇有提到ReduxReact是兩個沒有相關的套件,所以他們之間需要一座橋樑,而那座橋樑就叫做react-redux,我們得透過他讓React的組件能夠讀到Redux的資料,所以先來下載吧!

這裡提醒一下,如果大家是用昨天的專案繼續的話,別忘記要下載reactreact-dom,然後還要再幫babel多下載一個@babel/preset-react,最後最後把該loader放到webpack.config.js當中,而如果是使用之前在練習react的專案開發的話,就只需要另外裝reduxreact-redux

當看到這裡有點搞混不知道該怎麼做的話,也可以到我的gitHub這裡clone專案下來,下載後在該目錄下執行npm installnpm根據package.json的內容下載套件,也可以自行依照裡面的設定自行下載,順便熟悉一下專案開發的流程XD,而連結內有問題的話都可以在留言告訴我!

寫個store吧!

搞定事前準備後就可以開始動手了!先從新同學Redux開始,趁還沒忘掉在練習一次吧!

import {createStore} from "redux" //importRedux套件

//取得資料
const data = {message:[{key:"1",name:'神Q',message:'嗨!大家好啊!'},
{key:"2",name:'小馬',message:'早安啊!昨天有沒有好好發文?'},
{key:"3",name:'王子',message:'ㄛ!別說了,那真的超級累!'},
{key:"4",name:'神Q',message:'哈哈哈!加油啦!再一下就結束了!'},
{key:"5",name:'王子',message:'結束後我一定要爆睡一頓!'},]}

//設定動作,雖然現在是空的
const addMessage = article => ({type:'addMessage',payload:article})

//將描述各個動作對資料的行為
const rootReducer = (state = data, action) => {
    switch (action.type) {
        case "addMessage":
            break;
        default:
            return state
    }
}

//建立保管資料的store
const store = createStore(rootReducer)

//測試用加上去的,等等再把它拿掉:
window.store = store;
window.addMessage = addMessage;

昨天在講感覺還很複雜,但是今天做起來就覺得也滿單純XD,他主要分成幾個部分下去處理:

  1. 匯入redux套件的createStore方法。
  2. 設定動作的指令。
  3. 描述接受到指令要做什麼事情。
  4. createStore建立一個store

上方我把資料指定成前天簡單完成的留言板資料,我們先來確定一下資料是否正常被store保管了:
https://ithelp.ithome.com.tw/upload/images/20181019/20106935PzMYaQZhZP.png

可以看到他非常完美的保管著我們的資料,那現在就可以把測試的那兩行拿掉了!

寫一個組件吧!

接下來我們在資料夾內新增一個message.jsx(貼心小提醒:記得要把這個檔案加入webpack.config.js的打包對象中),並寫個class組件先簡單把訊息條列出來:

import React from "react"
import ReactDOM from "react-dom"

class MessageList extends React.Component {
    render(){
        let message = this.props.data.map((item)=>{
            return <li key={item.key}>{item.name}:{item.message}</li>
        })
        
        return(
            <ul>
                {message}
            </ul>
        )
    }
}

class MessageForm extends React.Component {
    render(){
        return <MessageList />
    }
}

ReactDOM.render(<MessageForm/>,document.getElementById('root'))

到這裡是不是還覺得輕輕鬆鬆!但是重頭戲來了,該怎麼把他們處理在一起呢?

react-redux登場!

首先我們先解釋一下react-redux這個套件,本文一開始有說,他是負責兩個套件之間的資料傳遞,那在這裡複習一下「React的最小單位是組件,而所有的資料為了一致性,會藉由props將資料從父組件流向子組件。」

現在我們將資料用redux統一管理,再將資料傳遞到組件中,這樣子的做法是不是很像父組件和子組件的關係?所以redux就是父組件,什麼父組件?

Provider

對的!雖然很突然,但是不要懷疑,react-redux套件提供了Provider組件的store屬性來傳遞上面用建立的store的資料,但是仔細想想,store把它寫在index.js中,message組件寫在message.jsx中,該怎麼把storeidnex.js傳到message.jsx呢?

我們可以用export default!把store丟出來,讓其他檔案可以透過import...from...的方式接收他,就像在使用其它套件一樣,如果好奇export default是怎麼運作的可以參考這篇文章,他講得非常清楚,所以得先在index.js的最下面增加一行export default store

export default store

再來就輪到message.jsx了!首先要做的是匯入需要的物件,除了剛剛的store外,還有更早之前講過的Provider組件:

//從react-redux匯入Provider組件
import {Provider} from "react-redux"
//從index.js中匯出store,如果大大的路徑和我不同,記得要改一下!
import store from "./index.js"

接下來要宣告一個mapStateToProps函式,我們將用它來指定需要哪些資料,例如上方的store資料長這樣:

const data = {message:[{key:"1",name:'神Q',message:'嗨!大家好啊!'},
{key:"2",name:'小馬',message:'早安啊!昨天有沒有好好發文?'},
{key:"3",name:'王子',message:'ㄛ!別說了,那真的超級累!'},
{key:"4",name:'神Q',message:'哈哈哈!加油啦!再一下就結束了!'},
{key:"5",name:'王子',message:'結束後我一定要爆睡一頓!'},]}

很明顯要取的資料就是存在message中那個陣列,所以mapStateToProps這麼寫:

//上方的data會被傳入這個function中的state
const mapStateToProps = state => {
    /*透過回傳的物件來指定要取的資料,
    這裡把message取走,然後key值用data回傳*/
    return { data: state.message }
}

好的!message組件有了,用來取資料的mapStateToProps也建好了,接下來要做連線了吧!用剛剛提到的Provider組件!等等嘛!先不要急,在這之前得用connect方法來將message組件和mapStateToProps連線,且他會回傳一個新的組件,不過我們剛剛還沒有import這個方法對吧!所以要記得先匯入後再使用:

//從react-redux匯入connect
import {connect} from "react-redux"
.
.
.
/*建立一個變數來存放connect回傳的組件,
注意這邊不是兩個參數哦!是兩個括號,
第一個給入mapStateToProps,第二個給要使用資料的組件*/
const List = connect(mapStateToProps)(MessageList)

到這裡不知道大家會不會好奇,為什麼要為取資料的function取名做mapStateToProps?直接叫做getdata不是簡單方便嗎?因為在redux官方文檔connect的函式接收的參數是這樣子:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

所以為了讓其他開發者,或是可能會看到程式碼的其他人一看就知道,這個函式就是要傳到connect中用來指定要從store中取得資料的!雖然使用getData也可以,不過其他人為了知道這是在做什麼的,就還要再追程式碼到connent才會知道,所以跟著大眾命名也是很重要的事情!

做了那麼多前置作業,總該輪到Provider了吧!不然我翻臉哦!沒錯!是該輪到他了!

使用前要注意哦!因為上面用connect所回傳的是一個組件,他會取代我們傳入的組件,也就是說上方的MessageList在這時候已經變成List了!所以我們不只要在MessageForm組件中增加Provider組件,還要把原本的MessageList改為List

class MessageForm extends React.Component {
    render(){
        return(
            //使用Provider組件記得要透過store屬性傳入import進來的store資料
            <Provider store={store}>
                //原本的MessageList已經被connect包成List了
                <List />
            </Provider>
        )
    }
}

天哪!做了那麼多事情,該不會還有吧?哈哈哈!已經沒了XD,我們一起打包後,開網頁看看成果吧!
https://ithelp.ithome.com.tw/upload/images/20181006/20106935iyqsOF4UzK.png

明明是簡單的畫面,但卻不知如何覺得很感動對吧XD,終於終於看見redux的成果了!而且React的家族感覺越來越強大!以下附上GitHub的連結,這一次動的檔案不只一個,所以直接給目錄,可以透過目錄點擊檔案看程式碼:
GitHub程式碼
GitPage頁面

今天先簡單熟悉Redux傳遞資料到React組件內props的過程,但是Redux能做的可不只是這樣子!大家應該還記得昨天有在redux做到異動資料這件事情吧!不過不要緊張,今天已經結束了XD,,明天會上面的進度開始做!把留言功能給做出來!


最後感謝各位大大的觀看!如果有任何文章內有任何問題,再麻煩留言告訴我!小弟會盡快修正會補充文章內容的!謝謝各位/images/emoticon/emoticon41.gif

參考資料:

  1. https://www.valentinog.com/blog/react-redux-tutorial-beginners/#React_Redux_tutorial_refactoring_the_reducer
  2. https://redux.js.org/basics/usagewithreact

上一篇
[筆記][React]當React遇上Redux(1)-初次見面
下一篇
[筆記][React]當React遇上Redux(3)-從React組件操作Reducer
系列文
一步一腳印的React旅程30

尚未有邦友留言

立即登入留言