我找到一篇 Redux 的初學教學,是一個外國人寫的,我順便翻寫他所做的文章,也方便我釐清觀念。
Getting started with create-react-app, Redux, React Router & Redux Thunk
首先用create-react-app 建立環境
create-react-app react-redux-example
cd react-redux-example
安裝套件
yarn add redux react-redux react-router-dom react-router-redux@next redux-thunk history
redux,react-redux,react-router-dom 不多解釋,react-router-redux
,主要是讓react-router-dom
的components 也納入redux
的方式管理, redux-thunk
是處理非同步問題(如串api)
#/src
一切檔案都建立在/src
裡面
這邊是設定react-router
與redux-thunk
的store
,引入redux的core去創造一個custom的全域storereact-router-redux
跟redux-thunk
是redux的中介層(middleware),一個概念,全都交給redux
// 稍後會再加進reducer,
You’ll notice we’re importing a file we haven’t yet created called rootReducer. This is essential to Redux. We’ll come back to Reducers later but for now, create a file called ./src/modules/index.js so we can satisfy our Store.
createStore
、compose
、applyMiddleware
1.createStrore 建立一個 Redux store,它掌控應用程式的完整 state tree。 在你的應用程式中應該只有單一一個 store。
2.compose:把 function 從右到左組合起來。
3.applyMiddleware:建立一個Middleware
1.routerMiddleware(history):你可以用到你的Redux Store中来取得action creator創建的acion。它會將這些操作重定向到提供的history實例。
HTML5的history API
import { createStore, applyMiddleware, compose } from 'redux'
import { routerMiddleware } from 'react-router-redux'
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory'
import rootReducer from './modules'
export const history = createHistory()
const initialState = {}
const enhancers = []
const middleware = [
thunk,
routerMiddleware(history)
]// 這邊把thunk跟history資料串起來
// 這段是偵測是否為開發模式
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
// 將function 組合起來
const composedEnhancers = compose(
applyMiddleware(...middleware),
...enhancers
)
const store = createStore(
rootReducer,
initialState,
composedEnhancers
)
export default store
1.combineReducers : 把reducing funcion 的物件轉換成一個可以傳給createStore的單一reducin funtion
1.routerReducer:同[reducer](https://chentsulin.github.io/redux/docs/basics/Reducers.html) 觀念,儲存router的資料,他會傳給剛剛的./store
import { combineReducers } from 'redux'
import { routerReducer } from 'react-router-redux'
export default combineReducers({
routing: routerReducer
})
這邊說明,components 會放到container coponents App
裡面。
Our router history is managed inside our Redux store which we created in the first section and is passed down via something called
ConnectedRouter
which we will implement later.
App
容器Containers,redux觀念裡,需要控制資料流的components 都會叫容器,也可以說是一個版,整個頁面都是包在App
內執行,
import React from 'react';
import { Route, Link } from 'react-router-dom'
import Home from '../home'
import About from '../about'
const App = () => (
<div>
<header>
<Link to="/">Home</Link>
<Link to="/about-us">About</Link>
</header>
<main>
<Route exact path="/" component={Home} />
<Route exact path="/about-us" component={About} />
</main>
</div>
)
刻出/home
的分頁
1.bindActionCreators:
1.connect:使用 connect() function 來產生 container component,它提供了許多有用的最佳化來避免不必要的重新 render。
1.bindActionCretors:把一個每個值都是 action creator 的物件轉換成另一個有同樣的 keys 的物件,不過每個 action creator 都被包進一個 dispatch 呼叫裡面,所以它們可以直接被呼叫。
bindActionCreators 唯一的使用情境是,當你希望傳遞一些 action creator 下去一個不知道 Redux 存在的 component,而你不希望把 dispatch 或是 Redux 的 store 傳遞給它。
1.push:看他作用應該跟history.push()是一樣觀念
import React from 'react'
import { push } from 'react-router-redux'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
const Home = props => (
<div>
<h1>Home</h1>
<p>Welcome home!</p>
<button onClick={() => props.changePage()}>Go to about page via redux</button>
</div>
)
const mapDispatchToProps = dispatch => bindActionCreators({
changePage: () => push('/about-us')
}, dispatch)
export default connect(
null,
mapDispatchToProps
)(Home)
import React from 'react'
export default () => (
<div>
<h1>About Us</h1>
<p>Hello Medium!</p>
</div>
)
明天待續