其實不想看react-redux、redux的源碼,平時不太喜歡用,尤其是簡單的頁面,然而總是會遇到複雜點的頁面的,所以還是要了解下,搜索了下,講react-redux、redux的文章很多,但是,好像都不太能理解,可能是風格不太一樣,沒辦法還是隻能自己看,看了就記錄下吧。
只講最簡單的使用涉及的東西,目前沒怎麼用中間件什麼的。react-redux版本6.0.1,redux版本4.0.1
使用的例子如下:
main.jsx文件
import ReactDOM from "react-dom";
import React from "react";
import Comp1 from "./comp1";
import {createStore} from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './reducers';
class App extends React.Component {
render() {
return (<div>
<Comp1 />
</div>);
}
}
const store = createStore(rootReducer, {
activeTab: 0,
});
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById("app"));
=====
comp1.jsx文件
import React, { Component } from "react";
import { connect } from 'react-redux';
import { changeTab } from './actions';
class Comp1 extends Component {
render() {
const {activeTab, changeTab} = this.props;
return (
<div>
<p>{activeTab}</p>
<button onClick={()=>changeTab(33)}>click</button>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({
activeTab: state.activeTab,
});
const mapDispatchToProps = (dispatch, ownProps) => ({
changeTab: (val) => {
dispatch(changeTab(val))
}
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Comp1);
=====
actions.js文件
export const changeTab = (val) => ({
type: 'change_tab',
activeTab: val
})
=====
reducers.js文件
export default (state = [], action) => {
switch (action.type) {
case 'change_tab':
return {...state, activeTab: action.activeTab};
default:
return state;
}
};
就是一個main裏面渲染了一個子組件,子組件渲染了一個p標籤和一個按鈕,初始化activeTab等於0,按一下按鈕變成了33。看一下整個過程涉及了哪些東西,首先是redux裏的createStore,然後是react-redux的Provider和connect,沒了,另外都是我們自己寫的東西了。
createStore
先來看一眼createStore幹了啥,打開redux/src/createStore.js看,createStore接收三個參數reducer, preloadedState, enhancer,最後一個不管它,第一個是我們自己寫的reducer,第二個是初始化的時候的state。先翻到createStore函數的最後,看到
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
其中getState和replaceReducer比較簡單,不說了,看subscribe這個名字應該能看出來這就是個發佈訂閱,subscribe是註冊監聽事件的函數,裏面有這麼一句nextListeners.push(listener)
,dispatch是調用reducer,並執行監聽事件的地方,可以在裏面看到
currentState = currentReducer(currentState, action)
...省略一些代碼
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
看到這裏你會問,是誰調用了subscribe呢?dispatch又是誰調用的呢?不出意外就是react-redux了
Provider
我們打開react-redux/src/components/Provider.js來看,發現Provider是個react組件,看Provider做了什麼
constructor(props) {
super(props)
const { store } = props // 這個store就是我們用redux的createStore生成的那個store
this.state = {
storeState: store.getState(), // 看一眼
store
}
}
componentDidMount() {
this._isMounted = true
this.subscribe() // 看一眼
}
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe() // 看一眼
this._isMounted = false
}
componentDidUpdate(prevProps) {
if (this.props.store !== prevProps.store) {
if (this.unsubscribe) this.unsubscribe() // 看一眼
this.subscribe() // 看一眼
}
}
...省略一些代碼
render() {
const Context = this.props.context || ReactReduxContext
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
構造函數和生命週期一看,基本上知道Provider做了什麼事情了吧,redux的createStore裏的subscribe函數就是Provider調用的,那麼再來看this.subscribe函數幹了啥
subscribe() {
const { store } = this.props
this.unsubscribe = store.subscribe(() => { // 調用redux的createStore裏的subscribe函數了
const newStoreState = store.getState()
if (!this._isMounted) {
return
}
this.setState(providerState => {
// If the value is the same, skip the unnecessary state update.
if (providerState.storeState === newStoreState) {
return null
}
return { storeState: newStoreState }
})
})
// Actions might have been dispatched between render and mount - handle those 看一眼這個註釋
const postMountStoreState = store.getState()
if (postMountStoreState !== this.state.storeState) {
this.setState({ storeState: postMountStoreState })
}
}
connect
還剩最後一個connect函數,就是調用dispatch的地方,這個部分怎麼說呢,我還沒看懂哈哈哈,比較複雜,我們的例子裏,mapDispatchToProps的參數dispatch其實就是redux的creatStore裏的那個dispatch,感興趣的同學可以深究,我這裏就不繼續了(逃走),實在不好意思,不過我們的流程已經通了,嗯,很好(?)。
總結
簡單總結一下:redux就是個發佈訂閱,提供了subscribe和dispatch,react-redux在Provider裏進行subscribe,connect的參數mapDispatchToProps裏的dispatch就是redux的dispatch,用react的context API來實現更新機制(這部分上面沒提到,也在connect相關的代碼裏,自己看?)