前面一篇文章我們分析了下Redux, 現(xiàn)在分析下React-Redux, React Redux 事實(shí)上是兩個(gè)獨(dú)立的產(chǎn)品杖刷,
應(yīng)用可以使用 React 而不使用Redux 傲绣,也可以使用 Redux 而不使用 React 捻勉,但是,如果兩者結(jié)合使用阳柔,沒有理由不使用一個(gè)名叫 react-redux 的庫這個(gè)庫能夠大大簡化代碼的書寫, 我們先看一官網(wǎng)redux的經(jīng)典案例, 從而進(jìn)一步了解react-redux轻专。
Redux的經(jīng)典案例
經(jīng)典案例加減
- 定義reducer函數(shù)根據(jù)action的類型改變state
- actions 定義指令
- 通過createStore創(chuàng)建store
- 調(diào)用store.dispatch()發(fā)出修改state的命令
import { createStore } from 'redux'
const reducer = (state = {count: 0}, action) => {
switch (action.type){
case 'INCREASE': return {count: state.count + 1};
case 'DECREASE': return {count: state.count - 1};
default: return state;
}
}
const actions = {
increase: () => ({type: 'INCREASE'}),
decrease: () => ({type: 'DECREASE'})
}
const store = createStore(reducer);
// 監(jiān)聽每一個(gè)dispatch后返回當(dāng)前最新的state
store.subscribe(() =>
console.log(store.getState())
);
store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}
現(xiàn)在可以運(yùn)用到React Component中了, 來看看吧
class Add extends Component {
render() {
return <div onClick={ () => store.dispatch(actions.addTodo()) }>Add</div>
}
}
React-Redux
Official React bindings for Redux.Performant and flexible
(Redux 官方提供的 React 綁定庫。 具有高效且靈活的特性被饿。)
react-redux 的兩個(gè)最主要功能
connect :連接數(shù)據(jù)處理組件和內(nèi)部UI組件四康;
Provider :提供包含 store的context
先來看看使用react-redux后的效果吧!
import { connect } from 'react-redux'
// 裝飾器寫法, 不懂的可以去腦補(bǔ)一下
@connect(
state => state,
action
)
class Add extends Component {
render() {
return <div onClick={ () => this.props.addTodo()) }>Add</div>
}
}
// 與裝飾器一個(gè)意思的寫法
export default connect(
state => state,
action
)
Provider源碼解析
Provider 能拿到關(guān)鍵的store并傳遞給每個(gè)子組件
class Provider extends Component {
getChildContext() {
return { [storeKey]: this[storeKey], [subscriptionKey]: null }
}
constructor(props, context) {
super(props, context)
this[storeKey] = props.store;
}
render() {
return Children.only(this.props.children)
}
}
即通過context api將store傳到子組件里面去狭握。
connect源理簡化解析
connect() 接收四個(gè)參數(shù), 它們分別是 mapStateToProps, mapDispatchToProps, mergeProps和options.
mapStateToProps是一個(gè)函數(shù)闪金,接受state并且返回一個(gè)對(duì)象,對(duì)象包括要傳遞給組件的屬性论颅,這里我們可以對(duì)state做篩選與過濾哎垦。因?yàn)槲覀冎恍枰謹(jǐn)?shù)據(jù)的部分?jǐn)?shù)據(jù)傳遞給組件。
// 例子來源Todo
function mapStateToProps(state) {
return {
visibleTodos: selectTodos(state.todos, state.visibilityFilter),
visibilityFilter: state.visibilityFilter
}
}
mapDispatchToProps同樣也是一個(gè)函數(shù)恃疯,返回要傳遞給組件的函數(shù)對(duì)象漏设。
// actions.js
export function addTodo(text) {
return { type: ADD_TODO, text }
}
export function completeTodo(index) {
return { type: COMPLETE_TODO, index }
}
export function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter }
}
export default {
addTodo, completeTodo, setVisibilityFilter,
}
// App.js
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actions, dispatch) }
}
mergeProps和options目前用的少, 暫不敘述
export default function(mapStateToProps,mapDispatchToProps){
return function(WrapedComponent){
class ProxyComponent extends Component{
static contextTypes = {
store:propTypes.object
}
constructor(props,context){
super(props,context);
this.store = context.store;
this.state = mapStateToProps(this.store.getState());
}
componentWillMount(){
this.unsubscribe = this.store.subscribe(()=>{
this.setState(mapStateToProps(this.store.getState()));
});
}
componentWillUnmount(){
this.unsubscribe();
}
render(){
let actions= {};
if(typeof mapDispatchToProps == 'function'){
actions = mapDispatchToProps(this.store.disaptch);
}else if(typeof mapDispatchToProps == 'object'){
actions = bindActionCreators(mapDispatchToProps,this.store.dispatch);
}
return <WrapedComponent {...this.state} {...actions}/>
}
}
return ProxyComponent;
}
}
1.state的返回
connect中對(duì)于Provided父組件上傳來的store,通過將狀態(tài)返回
mapStateToProps(this.store.getState());
2.通過 Redux 的輔助函數(shù) bindActionCreators(),用dispatch監(jiān)聽每一個(gè)action
bindActionCreators(mapDispatchToProps,this.store.dispatch);