20行代碼實(shí)現(xiàn)redux瞧省,50行代碼實(shí)現(xiàn)react-redux

timg (1).jpeg

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
沈跨,

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市兔综,隨后出現(xiàn)的幾起案子饿凛,更是在濱河造成了極大的恐慌,老刑警劉巖软驰,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涧窒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碌宴,警方通過(guò)查閱死者的電腦和手機(jī)杀狡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蒙畴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人命迈,你說(shuō)我怎么就攤上這事轨淌。” “怎么了恭陡?”我有些...
    開(kāi)封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)上煤。 經(jīng)常有香客問(wèn)我休玩,道長(zhǎng),這世上最難降的妖魔是什么劫狠? 我笑而不...
    開(kāi)封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任拴疤,我火速辦了婚禮,結(jié)果婚禮上独泞,老公的妹妹穿的比我還像新娘呐矾。我一直安慰自己,他們只是感情好懦砂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布蜒犯。 她就那樣靜靜地躺著,像睡著了一般荞膘。 火紅的嫁衣襯著肌膚如雪罚随。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天羽资,我揣著相機(jī)與錄音淘菩,去河邊找鬼。 笑死削罩,一個(gè)胖子當(dāng)著我的面吹牛瞄勾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弥激,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼进陡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了微服?” 一聲冷哼從身側(cè)響起趾疚,我...
    開(kāi)封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎以蕴,沒(méi)想到半個(gè)月后糙麦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丛肮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年赡磅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宝与。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡焚廊,死狀恐怖冶匹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咆瘟,我是刑警寧澤嚼隘,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站袒餐,受9級(jí)特大地震影響飞蛹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜灸眼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一卧檐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧焰宣,春花似錦泄隔、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至闸天,卻和暖如春暖呕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苞氮。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工湾揽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人笼吟。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓库物,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親贷帮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子戚揭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容