簡單實現了下redux,幫助理解redux的原理:css
// 維持應用的 state // 提供 getState() 方法獲取 state // 提供 dispatch(action) 方法更新 state // 經過 subscribe(listener) 註冊監聽器 // 經過 subscribe(listener) 返回的函數註銷監聽器 // createStore參數爲可變參數,第一個參數爲reducer,第二個參數爲初始state export function createStore(...arg){ let state = null; let reducer = arg[0]; // 使用第二個參數爲state初始化 if(arg.length > 1){state = arg[1]} // 保存監聽器的數據 let listeners = []; let getState = () => state; let subscribe = listener => listeners.push(listener) let dispatch = (action) =>{ //執行reducer函數,更新狀態 state = reducer(state,action) //遍歷listeners,執行之中的監聽器函數 listeners.forEach(listener => listener()) } return { getState, dispatch, subscribe } }
實現了redux的createStore方法,代碼沒幾行,應該能看懂吧。react
// 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;
把導入redux的代碼換成myredux便可,其餘使用和redux同樣。固然,redux的中間件並無實現。git
react-redux實現思路
藉助於context,把store經過Provider實現共享,這樣,在Provider內部的子組件就能夠得到store,而後在內部組件,須要獲取狀態的地方,使用consumer包裝,得到store,就能夠實現狀態共享了。
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>)
使用github
<Provider store={store}> <Container Consumer={Consumer}> </Container> </Provider>
問題是,<Container/>
裏面綁定了<Counter/>
並且還須要把<Consumer>
經過props傳到<Container/>
裏。
而且 展現組件裏也只能獲取一個狀態counter
redux
實現了connect
函數,用法和 react-redux
基本同樣,代碼以下:
connect.jside
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得到用戶須要的狀態 let mapState = mapStateToProps(store.getState()); for(let key in mapState){ this.state[key] = mapState[key] } } componentDidMount(){ let {store} = this.props //註冊監聽,這樣當state發生改變時,改變Inner的內部狀態,把這個新狀態在render中傳給了展現組件Comp,Comp就能夠實時獲取最新狀態了 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) //把狀態和方法傳入到展現組件中 return (<Comp {...actions} {...this.state} />) } } //connnect是一個高階組價,返回一個函數,接受展現組件爲參數,使用<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
基本上是如出一轍的,只不過把Provider
換成了Container
,不過我徹底能夠叫Provider
,一個名稱而已。函數
在App.js:this
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.jsspa
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);
已經能夠和react-redux
徹底同樣的用法。
固然,這裏的實現只是爲了幫助理解react-redux
內部是如何實現,並不必定是最好用的,實際工做中直接使用 react-redux
就行了。code
代碼放在Github上了,歡迎star: https://github.com/cooleye/co...,