import React from 'react';
import ReactDOM from 'react-dom';
import Counter1 from './components/Counter1';
import Counter2 from './components/Counter2';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<Counter1 />
<Counter2 />
</Provider>, document.getElementById('root'));
import React, { Component } from 'react'
import {connect} from 'react-redux';
import actions from '../store/actions/counter1';
//Counter1.props === {...state.counter1,...actions};
class Counter1 extends Component {
render() {
let {color,number,add1,minus1,changeColor} = this.props;
return (
<div style={{color}}>
<p>{number}</p>
<button onClick={add1}>+</button>
<button onClick={minus1}>-</button>
<button onClick={()=>changeColor('red')}>改成红色</button>
</div>
)
}
}
//把仓库中的状态映射为组件的属性对象 输入
let mapStateToProps = state=>state.counter1;
//把派发的动作映射为属性对象
//let mapDispatchToProps
export default connect(
mapStateToProps,
actions
)(Counter1);
react-redux的作用就是将state和action都映射到组件属性上
还有一种写法:
import React, { Component } from 'react'
import {connect} from '../react-redux';
import actions from '../store/actions/counter1';
import * as actionTypes from '../store/action-types';
class Counter1 extends Component {
render() {
let {color,number,add1,minus1,changeColor} = this.props;
return (
<div style={{color}}>
<p>{number}</p>
<button onClick={add1}>+</button>
<button onClick={minus1}>-</button>
<button onClick={()=>changeColor('red')}>改成红色</button>
</div>
)
}
}
//把仓库中的状态映射为组件的属性对象 输入
let mapStateToProps = state=>state.counter1;
//把dispatch方法映射为一个属性对象
let mapDispatchToProps = dispath=>({
add1(){
dispath({type:actionTypes.ADD1});
},
minus1(){
dispath({type:actionTypes.MINUS1});
},
changeColor(color){
dispath({type:actionTypes.CHANGE_COLOR,payload:color});
}
})
//把派发的动作映射为属性对象
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter1);
如果是函数组件,还可以使用useSelector和useDispatch两个hooks,分别对应mapStateToProps、mapDispatchToProps
import React from 'react'
import {useSelector,useDispatch} from '../react-redux';
import actions from '../store/actions/counter2';
let mapStateToProps = state=>state.counter2;
function Counter2(props){
//在函数组件的中可以使用useSelector替换掉mapStateToProps
let counter2 = useSelector(mapStateToProps);
let dispatch = useDispatch();
const {number,color}=counter2;
return (
<div style={{color}}>
<p>{number}</p>
<button onClick={()=>dispatch(actions.add2())}>+</button>
<button onClick={()=>dispatch(actions.minus2())}>-</button>
<button onClick={()=>dispatch(actions.changeColor('green'))}>改成绿色</button>
</div>
)
}
export default Counter2;
上述代码的执行流程分析:
1、当执行到import Counter1 from './components/Counter1'; 这一行时,会进入Counter1组件中,继续解析import {connect} from'../react-redux';,得到connect方法之后,会立刻执行(即将Counter1用高阶组件包装再作为导出组件的定义):
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter1);
2、接下来执行到了import { Provider } from 'react-redux';这一行,沿着它的import引用,我们可以追踪到:
export {default as Provider} from './Provider';
import ReactReduxContext from './ReactReduxContext';
export const ReactReduxContext = React.createContext(null);
所以这一行代码解析的时候,最终走到createContext,就会创建出一个Context对象:
function createContext(){
let context = { $$typeof: REACT_CONTEXT,_currentValue:null};
context.Provider = {
$$typeof:REACT_PROVIDER,
_context:context
}
context.Consumer = {
$$typeof:REACT_CONTEXT,
_context:context
}
return context;
}
3、接下来开始执行
ReactDOM.render(
<Provider store={store}>
<Counter1 />
<Counter3 />
</Provider>, document.getElementById('root'));
jsx编译之后为:
ReactDOM.render(
React.createElement(Provider, {
store: store
}, React.createElement(Counter1, null), React.createElement(Counter3, null))
,document.getElementById('root'));
render 方法中,遇到的第一层vdom的type应该是Provider对应的函数组件,即应该走mountFunctionComponent这个分支
mountFunctionComponent会传入props作为参数并直接执行,返回的vdom结构应该是:
{
type: ReactReduxContext.Provider,
props: {
value: {
store: props.store
}
},
children: props.children
}
紧接着,该vdom会再次传入createDOM方法中,然后再进入mountProvider分支中
这个分支里会将type._context._currentValue的值更新为props.value,在这里就是
type._context._currentValue === {
store: props.store
}
再将children传入createDOM中,之后在children渲染时就可以拿到这里的store的值了
接下来就开始渲染Counter1 Counter3这些children了
注意,其本质上是渲染的经过connect包装的高阶组件