在没有使用react-redux时
store实例有一个私有变量_state
state = store.getState()得到的是_state经过序列化在变成json对象,JSON.parse(JSON.stringify(this._state));
因此state和_state内容相同,但是修改state不会影响_state,事实上_state = reducer(state,action),
当执行store.dispatch(action)时,有两个步骤:第一,修改私有_state,_state = reducer(state,action),
第二,store.subscribe(fn)在监听_state的状态,只要store.dispatch(action)执行,不管_state是否发生变化,fn函数都会执行
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, bindActionCreators } from 'redux';
function reducer(state,action){
if (typeof state === 'undefined') return {name:'Jack',num:0};
switch (action.type){
case "changeName":
return Object.assign({},state,action.payload);
case "add":
return Object.assign({},state,{num: ++state.num});
default: return state;
}
}
const store = createStore(reducer);
let actions = {
changeName(name){
return{
type:'changeName',
payload:{name:name}
}
},
add(){
return{
type:'add'
}
}
}
actions = bindActionCreators(actions,store.dispatch)
class UI extends React.Component{
render(){
return(
<div>
<p>{this.props.name}</p>
<p>{this.props.num}</p>
<input onChange = {event => this.props.changeName(event.target.value)} />
<button onClick = {event => this.props.add()}>add</button>
</div>
)
}
}
function render(){
let state = store.getState();
ReactDOM.render(<UI changeName = {actions.changeName} add = {actions.add} name= {state.name} num = {state.num}/>,
document.getElementById('test'))
}
store.subscribe(render);
render();
使用react-redux时
本质就是Object.assign(this.props,store.getState(),actions); store.subscribe(ReactDOM.render())
function getState(state){
return state;
}
参数state就是store.getState(),store是由<Provider store={store}><UI/></Provider>中的store提供的。
function getActions(){return actions;
}
函数getActions()没有参数。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, bindActionCreators } from 'redux';
import {connect,Provider} from 'react-redux';
function reducer(state,action){
if (typeof state === 'undefined') return {name:'Jack',num:0};
switch (action.type){
case "changeName":
return Object.assign({},state,action.payload);
case "add":
return Object.assign({},state,{num: 1+state.num});
default: return state;
}
}
const store = createStore(reducer);
let actions = {
changeName(name){
return{
type:'changeName',
payload:{name:name}
}
},
add(){
return{
type:'add'
}
}
}
actions = bindActionCreators(actions,store.dispatch)
class UI extends React.Component{
render(){
return(
<div>
<p>{this.props.name}</p>
<p>{this.props.num}</p>
<input onChange = {event => this.props.changeName(event.target.value)} />
<button onClick = {event => this.props.add()}>add</button>
</div>
)
}
}
function getState(state){
return state;
}
function getActions(){
return actions;
}
UI = connect(getState,getActions)(UI);
ReactDOM.render(<Provider store={store}><UI/></Provider>,
document.getElementById('test'));
上面的代码可以将
actions = bindActionCreators(actions,store.dispatch);
function getActions(){return actions;}
这两条语句去掉
再将UI = connect(getState,getActions)(UI);修改成UI = connect(getState,actions)(UI);
因为当actions是json对象时,函数内部会自动调用bindActionCreators(actions,store.dispatch);
function getState(state,props){
return state;
}
当没有第二个参数props时,只会输出一次123
当有第二个参数props时,输出两次123
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, bindActionCreators } from 'redux';
import {connect,Provider} from 'react-redux';
function reducer(state,action){
if (typeof state === 'undefined') return {name:'Jack',num:0};
switch (action.type){
case "changeName":
return Object.assign({},state,action.payload);
case "add":
return Object.assign({},state,{num: 1+state.num});
default: return state;
}
}
const store = createStore(reducer);
let actions = {
changeName(name){
return{
type:'changeName',
payload:{name:name}
}
},
add(){
return{
type:'add'
}
}
}
class UI extends React.Component{
render(){
return(
<div>
<p>{this.props.name}</p>
<p>{this.props.num}</p>
<input onChange = {event => this.props.changeName(event.target.value)} />
<button onClick = {event => this.props.add()}>add</button>
</div>
)
}
}
function getState(state,props){
console.log(123);
return state;
}
UI = connect(getState,actions)(UI);
function render(name){
ReactDOM.render(<Provider store={store}><UI name={name}/></Provider>,
document.getElementById('test'));
}
render('Jack');
setTimeout(function(){
render('Mike')
},3000)
也可以将映射分开:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, bindActionCreators } from 'redux';
import {connect,Provider} from 'react-redux';
function reducer(state,action){
if (typeof state === 'undefined') return {name:'Jack',num:0};
switch (action.type){
case "changeName":
return Object.assign({},state,action.payload);
case "add":
return Object.assign({},state,{num: 1+state.num});
default: return state;
}
}
const store = createStore(reducer);
let actions = {
changeName(name){
return{
type:'changeName',
payload:{name:name}
}
},
add(){
return{
type:'add'
}
}
}
class OPT extends React.Component{
render(){
return(
<div>
<input onChange = {event => this.props.changeName(event.target.value)} />
<button onClick = {event => this.props.add()}>add</button>
</div>
)
}
}
OPT = connect(null,actions)(OPT);
class UI extends React.Component{
render(){
return(
<div>
<p>{this.props.name}</p>
<p>{this.props.num}</p>
<OPT/>
</div>
)
}
}
function getState(state){
return state;
}
UI = connect(getState)(UI);
ReactDOM.render(<Provider store={store}><UI name={name}/></Provider>,
document.getElementById('test'));
react-redux的实现:
Provider组件主要有以下下两个作用
在整个应用上包一层,使整个应用成为Provider的子组件
接收Redux的store作为props,通过context对象传递给子组件,所有的子组件都可以通过this.context.store取得store
import React from 'react'
import PropTypes from 'prop-types'
export class Provider extends React.Component{
static childContextTypes = {
store: PropTypes.object
}
constructor(props, context){
super(props, context)
this.store = props.store
}
getChildContext(){
return {store:this.store}
}
render(){
return this.props.children
}
}
connect实现:
import React from 'react';
import {bindActionCreators} from 'redux';
import PropTypes from 'prop-types';
export const connect = (mapStateToProps=state=>state,mapDispatchToProps={}) => (WrappedComponent) => {
class Connect extends React.Component {
static contextTypes = {
store: PropTypes.object
}
constructor(props,context){
super(props,coontext);
this.state={
props:{}
}
}
componontDidMount(){
const {store} = this.context;
store.subscribe(()=>this.update());
this.update()
}
update(){
const {store} = this.context;
const stateProps = mapStateToProps(store.getState());
const dispatchProps = bindActionCreators(mapDispatchToProps,store.dispatch)
this.setState({
props:{
...this.state.props,
...stateProps
...dispatchProps
}
})
}
render () {
const { store } = this.context
let stateProps = mapStateToProps(store.getState())
return <WrappedComponent {...this.state.props} />
}
}
使用了react-redux后,组件可以通过this.props得到store的状态。