redux的簡(jiǎn)陋版實(shí)現(xiàn)
簡(jiǎn)單實(shí)現(xiàn)了下redux扯夭,幫助理解redux的原理:
// 維持應(yīng)用的 state
// 提供 getState() 方法獲取 state
// 提供 dispatch(action) 方法更新 state
// 通過(guò) subscribe(listener) 注冊(cè)監(jiān)聽(tīng)器
// 通過(guò) subscribe(listener) 返回的函數(shù)注銷監(jiān)聽(tīng)器
// createStore參數(shù)為可變參數(shù),第一個(gè)參數(shù)為reducer鞍匾,第二個(gè)參數(shù)為初始state
export function createStore(...arg){
let state = null;
let reducer = arg[0];
// 使用第二個(gè)參數(shù)為state初始化
if(arg.length > 1){state = arg[1]}
// 保存監(jiān)聽(tīng)器的數(shù)據(jù)
let listeners = [];
let getState = () => state;
let subscribe = listener => listeners.push(listener)
let dispatch = (action) =>{
//執(zhí)行reducer函數(shù)交洗,更新?tīng)顟B(tài)
state = reducer(state,action)
//遍歷listeners,執(zhí)行之中的監(jiān)聽(tīng)器函數(shù)
listeners.forEach(listener => listener())
}
return {
getState,
dispatch,
subscribe
}
}
實(shí)現(xiàn)了redux的createStore方法橡淑,代碼沒(méi)幾行构拳,應(yīng)該能看懂吧。
如何使用梁棠?
// import {createStore} from 'redux'
import {createStore} from '../myredux'
import reducer from './reducer'
const initialState = {
counter:0,
title:'nihao'
}
const store = createStore(reducer,initialState)
export default store;
把導(dǎo)入redux的代碼換成myredux即可置森,其他使用和redux一樣。當(dāng)然符糊,redux的中間件并沒(méi)有實(shí)現(xiàn)凫海。
react-redux簡(jiǎn)陋版實(shí)現(xiàn)
react-redux實(shí)現(xiàn)思路
借助于context,把store通過(guò)Provider實(shí)現(xiàn)共享男娄,這樣行贪,在Provider內(nèi)部的子組件就可以獲得store漾稀,然后在內(nèi)部組件,需要獲取狀態(tài)的地方建瘫,使用consumer包裝崭捍,獲得store,就可以實(shí)現(xiàn)狀態(tài)共享了暖混。
版本一:
let Container = ({store}) => {
let [counter,setCounter] = useState(0);
useEffect(() =>{
store.subscribe(() => {
setCounter(store.getState().counter)
});
})
let add = () =>{
store.dispatch({
type:"INCREASE",
num:1
})
}
let min = () =>{
store.dispatch({
type:"DECREASE",
num:1
})
}
return <Counter counter={counter} min={min} add={add}/>
}
export default ({Consumer}) => (
<Consumer>
{ (store) => <Container store={store}/>}
</Consumer>)
使用
<Provider store={store}>
<Container Consumer={Consumer}>
</Container>
</Provider>
問(wèn)題是缕贡,<Container/>
里面綁定了<Counter/>
而且還需要把<Consumer>
通過(guò)props傳到<Container/>
里。
并且 展示組件里也只能獲取一個(gè)狀態(tài)counter
改進(jìn)版
實(shí)現(xiàn)了connect
函數(shù)拣播,用法和 react-redux
基本一樣晾咪,代碼如下:
connect.js
import React,{createContext} from 'react';
const {Provider,Consumer} = createContext();
export const Container = ({store,children}) => {
return (
<div>
<Provider value={store}>
{children}
</Provider>
</div>
)
}
class Inner extends React.Component{
constructor(props){
super(props)
this.state = {}
let {mapStateToProps,store} = this.props;
//從mapStateToProps獲得用戶需要的狀態(tài)
let mapState = mapStateToProps(store.getState());
for(let key in mapState){
this.state[key] = mapState[key]
}
}
componentDidMount(){
let {store} = this.props
//注冊(cè)監(jiān)聽(tīng),這樣當(dāng)state發(fā)生改變時(shí)贮配,改變Inner的內(nèi)部狀態(tài)谍倦,把這個(gè)新?tīng)顟B(tài)在render中傳給了展示組件Comp,Comp就可以實(shí)時(shí)獲取最新?tīng)顟B(tài)了
store.subscribe(()=>{
let storeState = store.getState();
for(let key in this.state){
this.setState({
[key]: storeState[key]
})
}
})
}
render() {
let {store,Comp,mapDispatchToProps} = this.props;
let actions = mapDispatchToProps(store.dispatch)
//把狀態(tài)和方法傳入到展示組件中
return (<Comp {...actions} {...this.state} />)
}
}
//connnect是一個(gè)高階組價(jià)泪勒,返回一個(gè)函數(shù)昼蛀,接受展示組件為參數(shù),使用<Consumer/>包裝圆存,傳入 store
export const connect = (mapStateToProps,mapDispatchToProps) =>{
return (Comp) => {
return () => (
<Consumer>
{ (store) =>( <Inner Comp={Comp} store={store} mapStateToProps={mapStateToProps} mapDispatchToProps={mapDispatchToProps}></Inner> ) }
</Consumer>)
}
}
如何使用:
使用方法叼旋,和react-redux
基本上是一模一樣的,只不過(guò)把Provider
換成了Container
,不過(guò)我完全可以叫Provider
,一個(gè)名稱而已沦辙。
在App.js:
import React from 'react';
import './App.css';
import store from './store'
import Cart from './components/Cart1'
import {Container} from './connect.js'
function App() {
return (
<Container store={store}>
<Cart/>
</Container>
);
}
export default App;
cart.js
import React from 'react'
import {connect} from '../connect'
let Counter = ({counter,title,min,add,changeTitle}) =>{
return (
<div>
<h1> {counter} </h1>
<h2> { title }</h2>
<button onClick={min}> - </button>
<button onClick={add}> + </button>
<button onClick={changeTitle}> update title </button>
</div>)
}
const mapStateToProps = (state) => {
return {
counter: state.counter,
title:state.title
}
}
const mapDispatchToProps = (dispatch) => {
return {
add: () => {
dispatch({type:"INCREASE",num:1})
},
min: () => {
dispatch({type:"DECREASE",num:1})
},
changeTitle() {
dispatch({type:"UPDATE_TITLE"})
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Counter);
已經(jīng)可以和react-redux
完全一樣的用法夫植。
當(dāng)然,這里的實(shí)現(xiàn)只是為了幫助理解react-redux
內(nèi)部是如何實(shí)現(xiàn)油讯,并不一定是最好用的详民,實(shí)際工作中直接使用 react-redux
就好了。
源碼
代碼放在Github上了陌兑,歡迎star: https://github.com/cooleye/connect.js
沈跨,