react-redux的代码,还挺多的,偷懒不想看,但是又怕别人问原理,所以就手撸一个来玩玩,超精简
惯例,先看react-redux的使用,这是一个按钮加一个p标签,初始化是0,点了以后随机生成数字,很简单,看不懂请看redux文档
index.jsx文件
import ReactDOM from "react-dom";
import React from "react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import Comp1 from "./comp1.jsx";
class App extends React.Component {
render() {
return (
);
}
}
// 定义一个reducer
const reducer = (state = [], action) => {
switch (action.type) {
case "change_num":
return { ...state, activeNum: action.activeNum };
default:
return state;
}
};
// createStore
const store = createStore(reducer, {
activeNum: 0
});
ReactDOM.render(
,
document.getElementById("root")
);
=================================================================
comp1.jsx文件
import React, { Component } from "react";
import { connect } from "react-redux";
// 定义action
const action = val => ({
type: "change_num",
activeNum: val
});
class Comp1 extends Component {
render() {
const { activeNum, changeNum } = this.props;
return (
{activeNum}
);
}
}
const mapStateToProps = (state, ownProps) => ({
activeNum: state.activeNum
});
const mapDispatchToProps = (dispatch, ownProps) => ({
changeNum: val => {
dispatch(action(val));
}
});
// 调用connect
export default connect(mapStateToProps, mapDispatchToProps)(Comp1);
我们关注下react-redux做了什么事情,一个是connect,一个是Provider,没了。
我们都知道redux是发布订阅,那么react-redux就是要把这套发布订阅用起来,因为我们都看过react-redux了,知道他用了react的Context,那么毫无疑问store在Provider传入之后,是作为Context.Provider的value,不然让人家怎么发布和订阅呢,于是我们yy了一下Provider的代码
// 创建一个Context肯定是要的
const Context = React.createContext("hehe");
export class Provider extends React.Component {
render() {
return (
// 不管怎样反正先把store给了value再说
{this.props.children}
);
}
}
这样写我们至少把使用Provider的样子写出来了对吧,贴一下方便回忆
ReactDOM.render(
,
document.getElementById("root")
);
然后就是connect了,我们看到它是一个高阶函数,传了两个mapxxx函数和组件,那么至少我们写的connect是个套了三层(两层?就这个意思)的函数,并且最里面一层返回了一个组件,这个组件订阅了store的变更,并且把store最新的值放到了被connect的Comp1上,我们yy一下这个组件的代码
import React from "react";
class Hoc extends React.Component {
constructor(props) {
super(props);
// 这个state存在的意义就是下面订阅的时候触发更新,当然,是没有性能优化的,谁叫我们是超精简
this.state = {};
}
componentDidMount() {
// 这里我们订阅了store的变更,这个props上的属性是怎么来的我们马上就知道了
this.props.store.subscribe(() => {
// 这里不触发一下更新的话,store.getState()是不会变的
this.setState({});
});
}
render() {
// 这里我们把两个mapxxx函数调用了一把,为什么这么调用,因为两个mapxxx函数就长了一副应该这么调用的脸
const { comp: Comp, mapState, mapDispath, store } = this.props;
const state = mapState(store.getState());
const dispatch = mapDispath(store.dispatch);
return ;
}
}
上面的注释说得不太清楚,我们来看看两个mapxxx函数,mapStateToProps需要传入一个state对象,返回一个对象,里面是一些属性,让Comp1可以在props上拿到,mapDispatchToProps需要传入一个dispatch函数,返回一个对象,里面是一些函数,让Comp1可以调用,那么显然一个就是store的getState返回值,一个是store的dispatch方法了(应该还挺显然的吧?),不显然也没事,我们先这么写着
const mapStateToProps = (state, ownProps) => ({
activeNum: state.activeNum
});
const mapDispatchToProps = (dispatch, ownProps) => ({
changeNum: val => {
dispatch(action(val));
}
});
这样的话connect长啥样我们也推导出来了,就像这样
// 第一层,接收mapxxx
export function connect(mapState, mapDispath) {
// 第二层,接收组件
return function(comp) {
// 终于到了Consumer的时候了
return function() {
return (
{store => (
)}
);
};
};
}
好了,到这里,把上面写的这些代码片段合起来,创建一个文件叫做hello-redux.jsx,并把我们顶部例子里的react-redux替换掉,就可以跑了,大家可以试一试
当然,因为是精简版,所以问题很多,比如mapxxx里有个ownProps的参数我们就没给,那个叫hehe的Context在多个地方使用会不会有问题,之类的,但是我们不管了()
以上,谢谢。