iThome
鐵人賽
30天
接續上一篇,我們已經把store整個套用在component內了,接下來就是看要如何把store內的state撈出來給component使用。
簡單介紹container,就是能把store的reducer state與action給取出來轉變成props傳入至component中,讓這些參數與動作能在之中自由呼叫使用。
照慣例,都一樣以實際我們實作的專案影片標記系統來改、舉例,先來看看哪個component是需要傳入reducer與action的。
首先是首頁 (.\src\components\Main\HomePage.jsx
) 的資料呈現與API抓取資料後設定,都需要透過reducer與action來進行,而container我也習慣把檔案集中在另一個containers
資料夾內,讓component與container分開 (有時候可能會有只需要component不需要container撈資料的情況,就可以看情況引用不同檔案)。
在container內依照component存放相對位置去建立檔案.\src\containers\Main\HomePage.jsx
:
import { connect } from 'react-redux'
// 把component引入
import HomePage from '../../components/Main/HomePage'
// 把藥使用的action引入
import { setData } from '../../action'
const mapStateToProps = (state) => ({
// 取出reducer內的state
home: state.home
})
const mapDispatchToProps = {
// 取出action
setData,
}
// 整合reducer與action進入props
export default connect(mapStateToProps, mapDispatchToProps)(HomePage)
更改HomePage引入的位置 (改成container的位置):
import React from 'react'
import { Box } from '@mui/material'
import { Route, Routes, Navigate } from 'react-router-dom'
import HomePage from '../containers/Main/HomePage' // 更改成container所在地
import WatchPage from './Main/WatchPage'
export default function Main() {
return (
<Box sx={{ bgcolor: '#999', flex: "1 1 auto" }}>
<Routes>
<Route path="/watch" element={<WatchPage />} />
<Route path="/" element={<HomePage />} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</Box>
)
}
我們將昨天設定的reducer home的預設資料取出來並console.log
試試看,看資料是否有成功取得。
import React, { useState, useEffect } from 'react'
import { Box } from '@mui/material'
import VideoCard from '../VideoCard'
export default function HomePage(props) {
const { home } = props // 取得reducer資料
const [data, setData] = useState(null)
console.log(home) // 查看是否成功
useEffect(() => {
getData()
}, [])
const getData = async () => {
const data = await fetch('http://localhost:5000/api/Notes').then(res => res.json())
setData(data)
}
return (
<Box sx={{ p: 3, display: "flex", flexWrap: "wrap", justifyContent: "center" }}>
{!!data && data.map(d =>
<VideoCard
key={d.v}
v={d.v}
title={d.title}
/>
)}
</Box>
)
}
console.log
結果:
可以看到有成功取出資料了!
先新增action,讓資料可以從component設定至reducer。
.\src\action\home.js
新增:
export const SET_DATA = "SET_DATA"
export const setData = (data) => action("SET_DATA", {data})
在reducer內建立相關應變措施改變initialState
。
.\src\reducer\home.js
:
// 把所有action引入
import * as action from '../action'
const initialState = {
data: null
}
export default (state = initialState, { type, ...payload }) => {
switch (type) {
// 用辨別type來看要採取甚麼行動更改state
case action.SET_DATA:
return {
...state,
data: payload.data,
}
default:
return state
}
}
將action從container中引入:
將component內的資料渲染與state變更狀態給替換掉,.\src\components\Main\HomePage.jsx
:
import React, { useState, useEffect } from 'react'
import { Box } from '@mui/material'
import VideoCard from '../VideoCard'
export default function HomePage(props) {
const { home, setData } = props
const { data } = home
console.log(home)
useEffect(() => {
// 第一次進入HomePage.jsx時去取得資料
getData()
}, [])
const getData = async () => {
// fetch取得API的資料
const data = await fetch('http://localhost:5000/api/Notes').then(res => res.json())
setData(data)
}
return (
<Box sx={{ p: 3, display: "flex", flexWrap: "wrap", justifyContent: "center" }}>
{/** 用.map的方式把array的資料一個一個渲染出來 */}
{!!data && data.map(d =>
<VideoCard
// key用來幫助React分辨哪些項目被改變、增加或刪除
key={d.v}
v={d.v}
title={d.title}
/>
)}
</Box>
)
}
可以看到更改後的畫面與資料依舊可以正常取得與呈現:
MarkPage
成React Redux的形狀再來就是如法炮製,按照同樣的方法把MarkPage
的標記也儲存在reducer之中,因為都是做一樣的事情,所以就不再列出來一一說明了,有興趣可以直接常看專案喔!
剩下最後兩天,也差不多剩下最後兩個部分,把API接上並齊全功能,與剩下的Redux Saga,所以應該是可以如期完成吧~
附上專案:
對資安或Mapbox有興趣的話也可以觀看我們團隊的鐵人發文喔~