最近在翻boss,感覺今年前端的風向標的確是react,火爆程度完全超過了其他框架,所以為了跟上潮流,不得不開始使用react了,既然用了react就免不了要研究一下redux。關於redux的使用場景,就看自己得業務需要了,就不多說了。這裡就簡單描述一下redux的使用原理和一些核心的結構,主要針對一些還沒有理解redux工作流的童鞋。 先看一下redux的流程圖
這是一個非常非常簡單的工作流程圖,通過互動觸發action,這時候會建立一個action物件,然後將這個物件丟給reducers,reducers會根據這個action的行為,對其攜帶的資料進行處理,然後merge到state,這裡就需要一個方法來完成這個過程,這個就是dispatch,state發生變化後,觸發監聽(這個應該算是個釋出訂閱)。這應該算是一個比較好理解的工具了,過程並不複雜,這個過程中reducer的邏輯是注入進來的,所以這個方法傳進來就好。。好,這樣我們就知道redux的核心結構是什麼樣的了:class MyRedux {
constructor(reducer, defaultState) {
this.reducer = reducer;
this.subscribeIndex = 0;
this.state = defaultState
? { ...defaultState }
: this.reducer(undefined, {
type: "qweqwe"
});
this.subscribeMap = {};
}
subscribe = func => {
let indexKey = this.subscribeIndex++;
this.subscribeMap[indexKey] = func;
return () => {
delete this.subscribeMap[indexKey];
};
};
getState = () => {
return this.state;
};
dispatch = action => {
this.state = Object.assign(this.state, this.reducer(this.state, action));
Object.keys(this.subscribeMap).forEach(key => {
let subscribeFunc = this.subscribeMap[key];
subscribeFunc && subscribeFunc();
});
};
}
複製程式碼
大概解釋一下,constructor裡面就是接受reducers和初始化state,這裡的'qweqwe'是隨便寫的,原始碼中用的是'@@redux/INIT',subscribe就是註冊監聽,dispatch就是接受action然後通過reducers改變state,接著就觸發註冊的監聽。 應該很好理解吧,再看一下redux其他的一些方法。
export function CreateStore(reducer) {
return new MyRedux(reducer);
}
export function combineReducers(reducerMap) {
return function(state = {}, action) {
const nextState = {};
Object.keys(reducerMap).forEach(key => {
const reducer = reducerMap[key];
nextState[key] = reducer(state[key], action);
});
return nextState;
};
}
複製程式碼
這兩個方法就比較簡單了,建立store和合並reducers。 接下來就是provider,這個其實只要理解了context就好辦了,來我們直接看程式碼:
const MyReactContext = React.createContext();
export class MyProvider extends Component {
static propTypes = {
store: PropTypes.instanceOf(MyRedux),
children: PropTypes.node
};
render() {
const MyReactProvider = MyReactContext.Provider;
return (
<MyReactProvider value={this.props.store}>
{this.props.children}
</MyReactProvider>
);
}
}
複製程式碼
這是一個react節點,直接建立一個context,然後把子節點扔在provider裡面就行了,這樣就能在這個裡面通過consumer獲取到store了。最後就是connect了,這個對一些初學者來說還是有些繞的,使用的時候需要傳入兩次引數,一次是需要併入props的一些引數,一個是當前的元件,這塊是柯里化一個很好的應用,個人感覺柯里化的好處就是能把引數分類,切換頻次低的可以複用,不過用的還是比較少,理解太到位。接著說connect,這個是高階元件的用法,我們在外層函式傳入併入的引數,然後返回一個函式,這個函式接受一個react元件,返回一個新的包裝過後的元件。來看一下程式碼:
export function MyConnect(mapStateToProps, mapDispatchToProps) {
function connectHOC(RawComponent) {
return class NewComponent extends Component {
unsubscribe = null;
constructor(props) {
super(props);
this.state = {
};
}
setSubscribe(store) {
if (!this.unsubscribe) {
this.unsubscribe = store.subscribe(() => {
this.setState(prevState => {
return {
};
});
});
}
}
componentWillUnmount() {
this.unsubscribe && this.unsubscribe();
}
getState = store => {
if (!mapStateToProps) {
return store.getState();
} else {
return mapStateToProps(store.getState(), this.props);
}
};
getDispatch = store => {
if (!mapDispatchToProps) {
return {
dispatch: store.dispatch
};
} else {
return mapDispatchToProps(store.dispatch, this.props);
}
};
render() {
const MyReactConsumer = MyReactContext.Consumer;
return (
<MyReactConsumer>
{store => {
this.setSubscribe(store);
let mixedProps = {
...this.getState(store),
...this.getDispatch(store),
...this.props
}
return <RawComponent store={store} {...mixedProps} />;
}}
</MyReactConsumer>
);
}
};
}
return connectHOC;
}
複製程式碼
這就是connect方法,通過高階元件返回一個被包裝起來的元件,這樣就能消費store了,還有在render 的時候,我們要把監聽事件註冊進來,這個方法目前只是用來重新渲染,這個地方用的是函式式的方法,因為setState是非同步的,不可信(這個地方只是為了重新渲染,不要在意沒有東西。。。)。不過個人認為這個地方可以做更多的事情,不過老師告訴我沒有實際場景就不要過度設計,屬於偽設計(受教了。。。),最後要記得刪除監聽。
以上就是簡易的redux程式碼,應該還比較好理解的把。感覺能看的下去的話,麻煩點個贊哈。。
最後,,,求一份內推。。。