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 (
<div>
<Comp1 />
</div>
);
}
}
// 定義一個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(
<Provider store={store}>
<App />
</Provider>,
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 (
<div>
<p>{activeNum}</p>
<button onClick={() => changeNum(Math.random())}>click</button>
</div>
);
}
}
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再說
<Context.Provider value={this.props.store}>
{this.props.children}
</Context.Provider>
);
}
}
這樣寫我們至少把使用Provider的樣子寫出來了對吧,貼一下方便回憶
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
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 <Comp {...state} {...dispatch} />;
}
}
上面的註釋說得不太清楚,我們來看看兩個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 (
<Context.Consumer>
{store => (
<Hoc
comp={comp}
store={store}
mapState={mapState}
mapDispath={mapDispath}
/>
)}
</Context.Consumer>
);
};
};
}
好了,到這裏,把上面寫的這些代碼片段合起來,創建一個文件叫做hello-redux.jsx,並把我們頂部例子裏的react-redux替換掉,就可以跑了,大家可以試一試
當然,因爲是精簡版,所以問題很多,比如mapxxx裏有個ownProps的參數我們就沒給,那個叫hehe的Context在多個地方使用會不會有問題,之類的,但是我們不管了(😂)
以上,謝謝。