react-redux 是 Redux 作者封裝的一個第三方模組,它對 Redux 進行簡化提供額外的 API (像是Provider、connect等),那並不是一定要用其實也可以用 Redux 就好,接下來會說明一下 Redux 和 react-redux 流程上的差異,我們今天實作所使用的也是 react-redux
,所以也先 npm install react-redux --save
裝好套件唷。
Redux 的流程: component -> dispatch(action) -> reducer -> subscribe -> getState -> component
react-redux 的流程: component -> actionCreator(data) -> reducer -> component
Provider 傳遞了 Store 到每個元件,讓所有元件都有辦法獲取 Store 裡的資料,以及 dispatch(action)
Provider 是對 Redux 中的 Store 的 subscribe, dispatch, getState 的一個集合,它接收了 Redux 創建的 store ,並根據 component 裡的 mapStateToProps 上要求將資料從 store 中取出,以 props 形式傳給 Component。
connect 是用來連接 React Component 和 Redux Store 的,connect 最終會返回一個已經與 Redux Store 連接的 Component
connect 總共可以接收四個參數:mapStateToProps、mapDispatchToProps、mergeProps、options。
import { connect } from 'react-redux';
const VisibleComponent = connect(mapStateToProps, mapDispatchToProps,mergeProps, options)(ComponentName);
mapStateToProps 就是將 Store 裡 State 的資料作為 Props 傳送到 Component 裡
mapStateToProps 接收兩個參數,State 指的是 Store 裡的 State,而 ownProps 代表的是當下Component 裡的 props,這個函數會去訂閱 Store 裡的 State,如果有變化就會執行這個函數;如果有傳入第二個參數,當本身的 props 有變化的時候也會觸發這個函數
const mapStateToProps = (state) => {
return {
storeListValue: state.storeListValue
}
}
mapDispatchToProps 定義了哪些 Component 裡的操作應該被當作 Action 並傳給 Store
mapDispatchToProps 可以是一個函數也可以是 Object,如果是函數主要是在定義 Component 如何發出這個 Action,其實就是調用 dispatch 這個方法。
const mapDispatchToProps = (dispatch, ownProps) => {
return {
increase: (...args) => dispatch({ type: 'BeTriggeredAction'}),
}
}
主要是將 mapStateToProps() 與 mapDispatchToProps() 返回的 props 跟自己本身的 props 合成新的 props 傳入 Component 內。
const mergeProps = () => {
return Object.assign({}, ownProps, stateProps, dispatchProps)
}
這裏將實作一個簡單的計算機,有 + - * 功能的為例子。
檔案位置 src/reducer.js
import React from 'react';
import { connect } from 'react-redux';
const initialValue = 300;
const increase = {
type: '加'
}
const decrease = {
type: '減'
}
const mutiplication = {
type: '雙倍'
}
const reducer = (state = initialValue, action) => {
switch (action.type) {
case '加':
return state += 1;
case '減':
return state -= 1;
case '雙倍':
return state *= 2;
default:
return state;
}
}
export default reducer;
檔案位置 src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducer';
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
檔案位置 src/App.js
import React from 'react';
import { connect } from 'react-redux';
class App extends React.Component {
render() {
const { Increase, Decrease, Double } = this.props;
return (
<div className="App">
<h2>當下數字為: {this.props.number}</h2>
<button onClick={Increase}>增加</button>
<button onClick={Decrease}>減少</button>
<button onClick={Double}>雙倍</button>
</div>
)
}
}
// 需要渲染什麼數據
function mapStateToProps(state) {
return {
number: state
}
}
// 需要觸發什麼行為
function mapDispatchToProps(dispatch) {
return {
Increase: () => dispatch({ type: '加' }),
Decrease: () => dispatch({ type: '減' }),
Double: () => dispatch({ type: '雙倍' })
}
}
export default App = connect(mapStateToProps, mapDispatchToProps)(App);