先熟悉兩個方法(大概瀏覽下即可,根據(jù)后面的例子對照學(xué)習(xí))
bindActionCreator(actionCreators, dispatch)
使用dispatch將一個action creator(action創(chuàng)建函數(shù),前面有提到)禽炬,或者一個 value 是 action creator 的對象進(jìn)行包裝曾我,以便可以在react組件里面直接調(diào)用他們。
入?yún)?/strong>
- actionCreators :Function | Object
- dispatch: Function撵彻。
第一個入?yún)⑹莂ction creator函數(shù)
const toggleTodo = (id) => {
return {
type: 'TOGGLE_TODO',
id
};
};
let boundActionCreators = bindActionCreators(toggleTodo, dispatch);
//此時boundActionCreators = (id) => dispatch(toggleTodo(id));
第一個入?yún)⑹莢alue為action action對象
const removeTodo = {
removeTodo : id => {
type: 'REMOVE_TODO',
id
}
};
let boundActionCreators = bindActionCreators(removeTodo, dispatch);
//此時boundActionCreators = (id) => dispatch(removeTodo(id));
所以bindActionCreator實現(xiàn)思路就是
- 判斷傳入第一個的參數(shù)是否是object钓株,如果是函數(shù)实牡,就直接返回一個包裹dispatch的函數(shù)
- 如果是object,就根據(jù)相應(yīng)的key轴合,生成包裹dispatch的函數(shù)即可
(隨口一問:為什么要用dispath包裹呢 创坞?想想上一篇的內(nèi)容吧~~)
connect(...)
- 將Redux store和React組件聯(lián)系在一起
- connenct并不會改變它“連接”的組件,而是提供一個經(jīng)過包裹的connect組件受葛。
connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)
入?yún)?/strong>
接受4個不同的题涨,可選擇的參數(shù)。按照慣例总滩,他們被稱為:
- mapStateToProps?: Function
- mapDispatchToProps?: Function | Object
- mergeProps?: Function
- options?: Object
mapStateToProps?: (state, ownProps?) => Object
- 用于建立組件跟store的state的映射關(guān)系
- 作為一個函數(shù)纲堵,它可以傳入兩個參數(shù)(state, ownProps?)闰渔,結(jié)果一定要返回一個object
- 傳入mapStateToProps之后席函,會訂閱store的狀態(tài)改變,在每次store的state發(fā)生變化的時候冈涧,都會被調(diào)用
- ownProps代表組件本身的props茂附,如果寫了第二個參數(shù)ownProps,那么當(dāng)prop發(fā)生變化的時候督弓,mapStateToProps也會被調(diào)用营曼。例如,當(dāng) props接收到來自父組件一個小小的改動愚隧,那么你所使用的 ownProps 參數(shù)蒂阱,mapStateToProps 都會被重新計算)。
- 如果不想訂閱store的更新狂塘,在connect()中录煤,可以直接將mapStateToProps方法用null 或者undefined代替
一個參數(shù)
const mapStateToProps = state => ({ todos: state.todos })
兩個參數(shù)
const mapStateToProps = (state, ownProps) => ({
todo: state.todos[ownProps.id]
})
mapDispatchToProps?: Object | (dispatch, ownProps?) => Object
mapDispatchToProps用于建立組件跟store.dispatch的映射關(guān)系
它可以是一個對象或者是帶有兩個參數(shù)(dispatch, ownProps?)的函數(shù) ,結(jié)果一定要返回一個object
如果mapDispatchToProps是一個函數(shù),調(diào)用時最多使用兩個參數(shù)荞胡,如下
一個參數(shù)
const mapDispatchToProps = dispatch => {
return {
// dispatching plain actions
increment: () => dispatch({ type: 'INCREMENT' }),
decrement: () => dispatch({ type: 'DECREMENT' }),
reset: () => dispatch({ type: 'RESET' })
}
}
兩個參數(shù)
// binds on component re-rendering
;<button onClick={() => this.props.toggleTodo(this.props.todoId)} />
// binds on `props` change
const mapDispatchToProps = (dispatch, ownProps) => {
toggleTodo: () => dispatch(toggleTodo(ownProps.todoId))
}
- 如果mapDispatchToProps是一個object辐赞,其中這個object所對應(yīng)的value必須是actionCreator,這樣redux里面會自動幫我們調(diào)用bindActionCreator
const mapDispatchToProps = {
...action
}
- 如果想使用默認(rèn)的dispath方法硝训,在connect()中响委,可以將mapDispatchToProps方法用null代替
// do not pass `mapDispatchToProps`
connect()(MyComponent)
connect(mapState)(MyComponent)
connect(
mapState,
null,
mergeProps,
options
)(MyComponent)
mergeProps?: (stateProps, dispatchProps, ownProps) => Object
- 將mapStateToProps(), mapDispatchToProps()以及組件自身的props合并
- 暫時忽略,期待后續(xù)
options?: Object
- 暫時忽略窖梁,期待后續(xù)
廢話不說赘风,上圖
這是一個很常見的“輸入框校驗”需求,根據(jù)用戶輸入的數(shù)字纵刘,判斷是否符合要求(輸入必須為1000的整數(shù)倍)邀窃,給予相應(yīng)的文字提示。
下面我們就使用react-redux來處理這個需求吧~~
- 動手寫代碼之前,先考慮下有哪些state
“錯誤信息提示” -errorMsg
- 各個state有哪些操作可以修改
既是考慮下action的type的取值
action.js
--------------------------
showMutipleMsg(errorMsg){
type:"MUTIPLE_ERROR_MESSAGE",
errorMsg:"輸入金額需為1瞬捕,000的整數(shù)"
}
showMinMsg(errorMsg){
type:"MIN_ERROR_MESSAGE",
errorMsg:"輸入金額需不能小于2鞍历,000元"
}
--------------------------
//上面兩個action都是對一個state的描述,操作類型相似肪虎,我們可以通過“action創(chuàng)建函數(shù)”改寫:
changeErrorMsg(errorMsg){
return {
type:"CHANGE_ERROR_MESSAGE",
errorMsg
}
}
//action創(chuàng)建函數(shù)劣砍,其實就是生成 action 的方法,這樣做將使 action 更容易被移植和測試。
觸發(fā)函數(shù)扇救,子分類的reducer
pageReducer.js
//校驗輸入框的reducer
export const pageReducer = function(state={errorMsg:''},action) {
switch (action.type) {
case 'CHANGE_ERROR_MESSAGE':
console.log("action==",action);
return Object.assign({}, state, {
errorMsg: action.errorMsg
})
default:
return state
}
}
//根部reducer
rootReducer.js
import { combineReducers } from 'redux'
import {pageReducer} from './pageReducer'
//這里有意使用了combineReducers
const rootReducer = combineReducers({
page:pageReducer,
});
export default rootReducer;
被觸發(fā)的組件
InputError.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
class InputError extends Component {
static propTypes = {
errorMsg: PropTypes.string
}
render () {
return (
<div className="error-message">
{this.props.errorMsg }
</div>
)
}
}
const mapStateToProps = (state) => {
console.log(state);
return {
errorMsg: state.page.errorMsg
}
}
export default connect(mapStateToProps)(InputError)
組件中的觸發(fā)
Input.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {changeErrorMsg} from '../actions/actionPage'
class Input extends Component {
constructor(props){
super(props);
this.handleSwitchError = this.handleSwitchError.bind(this);
}
static propTypes = {
onSwitchErrorMessage: PropTypes.func
}
handleSwitchError (event) {
/**
* 各種計算校驗刑枝,這里只做了1000整數(shù)倍的校驗如果不符合規(guī)范,dispatch action 去顯示錯誤信息
*
*/
let errorMsg = '';
const value = event.target.value;
if( value % 1000 !== 0){
errorMsg = '請輸入1000的整數(shù)倍';
}
if (this.props.onSwitchErrorMessage) {
this.props.onSwitchErrorMessage(errorMsg);
}
}
render () {
return (
<div>
<input onChange={ this.handleSwitchError } maxLength={9}/>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSwitchErrorMessage: (errorMsg) => {
dispatch(changeErrorMsg(errorMsg))
}
}
}
export default connect(null, mapDispatchToProps)(Input);
入口文件
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import Input from './containers/Input'
import InputError from './containers/InputError'
import rootReducer from './reducers/rootReducer'
import './index.css'
const store = createStore(rootReducer);
//console.log("=====store.getState====",store.getState());
class Index extends Component {
render () {
return (
<div>
<Input />
<InputError/>
</div>
)
}
}
ReactDOM.render(
<Provider store={store}>
<Index />
</Provider>,
document.getElementById('root')
)
下一章 react-redux--異步Action