前面雖然簡單的講了如何在react
中集成redux
,可是那只是簡單的講講而已,這一章將會仔細講講如何在react
中使用reudx
react
查看前邊的栗子:git
import {createStore} from 'redux' import React from 'react' import ReactDom from 'react-dom' //reducer const counter = (state = 0, action) => { switch (action.type) { case ACTION_INCREMENT: return state + 1 case ACTION_DECREMENT: return state - 1 default: return state } } // action const ACTION_INCREMENT = 'INCREMENT' const ACTION_DECREMENT = 'DECREMENT' // action creator const increment = () => ({ type: ACTION_INCREMENT }) const decrement = () => ({ type: ACTION_DECREMENT }) // store const store = createStore(counter) // react // // 組件 class App extends React.Component { constructor() { super() // 初始化 state this.state = { counter: 0 } // 監聽 store 變化, store 變化的時候更新 counter this.unSub=store.subscribe(() => { this.setState({ counter: store.getState() }) }) } // 組件銷燬的時候取消訂閱 componentWillUnmount(){ this.unSub() } render() { return <div> <p>{this.state.counter}</p> <button onClick={() => { store.dispatch(increment()) }}>+ </button> <button onClick={() => { store.dispatch(decrement()) }}>- </button> </div> } } ReactDom.render( <App/>, document.getElementById('app') )
爲了讓組件能夠響應redux
的變化,咱們寫了一些代碼:github
.... // 監聽 store 變化, store 變化的時候更新 counter this.unSub=store.subscribe(() => { this.setState({ counter: store.getState() }) }) .... // 組件銷燬的時候取消訂閱 componentWillUnmount(){ this.unSub() }
若是咱們有大量的組件須要綁定redux
,那麼寫這些代碼就顯得很是冗餘了
這一章要作的事就是優化掉這個東西redux
connect
方法這裏用了一個react
的HOC
,參數是一個組件,返回值也是一個組件,可是返回的組件被添加了一個props
,也就是state
。connect
方法爲每一個組件添加了響應store
數據變化的能力,在store.dispatch
調用的時候,會修改組件的props
,讓組件重繪,從而達到react
組件和redux
綁定可是又不須要寫太多樣板代碼
connect
app
const connect = (WrappedComponent) => { return class Control extends React.Component { constructor() { super() this.state = { state: 0 } this.unSub = store.subscribe(() => { this.setState({ state: store.getState() }) }) } componentWillUnmount() { this.unSub() } render() { return <WrappedComponent state={this.state.state}/> } } }
完整源碼dom
import {createStore} from 'redux' import React from 'react' import ReactDom from 'react-dom' //reducer const counter = (state = 0, action) => { switch (action.type) { case ACTION_INCREMENT: return state + 1 case ACTION_DECREMENT: return state - 1 default: return state } } // action const ACTION_INCREMENT = 'INCREMENT' const ACTION_DECREMENT = 'DECREMENT' // action creator const increment = () => ({ type: ACTION_INCREMENT }) const decrement = () => ({ type: ACTION_DECREMENT }) // store const store = createStore(counter) const connect = (WrappedComponent) => { return class Control extends React.Component { constructor() { super() this.state = { state: 0 } this.unSub = store.subscribe(() => { this.setState({ state: store.getState() }) }) } componentWillUnmount() { this.unSub() } render() { return <WrappedComponent state={this.state.state}/> } } } // 子組件 class SubCom extends React.Component { render(){ return <p>{this.props.state}</p> } } // 包裹這個組件 let ReduxSubCom=connect(SubCom) // react 組件 class App extends React.Component { constructor() { super() } render() { return <div> <ReduxSubCom/> <button onClick={() => { store.dispatch(increment()) }}>+ </button> <button onClick={() => { store.dispatch(decrement()) }}>- </button> </div> } } // 包裹組件 let ReduxApp = connect(App) ReactDom.render( <ReduxApp/>, document.getElementById('app') )
connect
方法,消除訂閱整個state
樹的影響雖然已經實現了將state
和組件綁定,可是咱們綁定的是整個state
,若是state
樹很大而且組件不少,那這個無畏的性能消耗太兇了。
redux
結構const counter = (state = {counter: 0, num: 0}, action) => { switch (action.type) { case ACTION_INCREMENT: return {...state, ...{counter: ++state.counter}} case ACTION_DECREMENT: return {...state, ...{counter: --state.counter}} default: return state } }
connect
方法,返回一個函數,並修改props
傳參:const connect = (mapStateToProps) => { return (WrappedComponent) => class Control extends React.Component { constructor() { super() this.state = { state: {} } this.unSub = store.subscribe(() => { let state = mapStateToProps(store.getState()) this.setState({ state: state }) }) } componentWillUnmount() { this.unSub() } render() { return <WrappedComponent {...this.state.state}/> } } }
APP
組件中的props
訪問方式class App extends React.Component { constructor() { super() } componentWillReceiveProps(nextProps) { console.log(nextProps) } render() { return <div> <p>{this.props.counter}</p> <button onClick={() => { store.dispatch(increment()) }}>+ </button> <button onClick={() => { store.dispatch(decrement()) }}>- </button> </div> } }
connect
調用let ReduxApp = connect((state) => { return { counter: state.counter } })(App)
connect
,讓代碼中再也不調用store.dispatch
,不在依賴redux
修改connect
方法,除了吧state
映射到props
上,也把dispatch
給映射上去了,這樣組件就感覺不到redux
的存在了ide
const connect = (mapStateToProps, mapDispatchToProps) => { return (WrappedComponent) => class Control extends React.Component { constructor() { super() // 第一次初始化 let props = mapStateToProps(store.getState()) let actions = mapDispatchToProps(store.dispatch) this.state = { props: {...props,...actions} } this.unSub = store.subscribe(() => { // 變化的時候再次計算 let props = mapStateToProps(store.getState()) let actions = mapDispatchToProps(store.dispatch) this.setState({ props: {...props,...actions} }) }) } componentWillUnmount() { this.unSub() } render() { return <WrappedComponent {...this.state.props}/> } } }
修改connect
調用,將dispatch
映射到組件上函數
let ReduxApp = connect( (state) => { return { counter: state.counter } }, (dispatch) => { return { increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), } } )(App)
修改App
組件,再也不使用store.dispatch
,而是使用connect
傳遞過來的dispatch
,讓組件不依賴redux
性能
class App extends React.Component { constructor(props) { super() } render() { const {counter,increment,decrement}=this.props return <div> <p>{counter}</p> <button onClick={increment}>+ </button> <button onClick={decrement}>- </button> </div> } }
完整源碼優化
import {createStore} from 'redux' import React from 'react' import ReactDom from 'react-dom' //reducer const counter = (state = {counter: 0, num: 0}, action) => { switch (action.type) { case ACTION_INCREMENT: return {...state, ...{counter: ++state.counter}} case ACTION_DECREMENT: return {...state, ...{counter: --state.counter}} default: return state } } // action const ACTION_INCREMENT = 'INCREMENT' const ACTION_DECREMENT = 'DECREMENT' // action creator const increment = () => ({ type: ACTION_INCREMENT }) const decrement = () => ({ type: ACTION_DECREMENT }) // store const store = createStore(counter) const connect = (mapStateToProps, mapDispatchToProps) => { return (WrappedComponent) => class Control extends React.Component { constructor() { super() // 第一次初始化 let props = mapStateToProps(store.getState()) let actions = mapDispatchToProps(store.dispatch) this.state = { props: {...props,...actions} } this.unSub = store.subscribe(() => { // 變化的時候再次計算 let props = mapStateToProps(store.getState()) let actions = mapDispatchToProps(store.dispatch) this.setState({ props: {...props,...actions} }) }) } componentWillUnmount() { this.unSub() } render() { return <WrappedComponent {...this.state.props}/> } } } // react 組件 class App extends React.Component { constructor(props) { super() } render() { const {counter,increment,decrement}=this.props return <div> <p>{counter}</p> <button onClick={increment}>+ </button> <button onClick={decrement}>- </button> </div> } } let ReduxApp = connect( (state) => { return { counter: state.counter } }, (dispatch) => { return { increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), } } )(App) ReactDom.render( <ReduxApp/>, document.getElementById('app') )
reat-redux
以上效果就和上一章的效果一致,是一個counter
,在這裏咱們一步一步去除了樣板代碼,並將redux
從組件中移除,若是隻看App
組件,根本感受不到redux
的存在,但redux
又確實存在,若是有一天你要去掉redux
,就能夠作到不影響組件了。這裏的connect
其實不須要本身寫,已經有好的實現了:react-redux
// 引入`react-redux` import {Provider, connect} from 'react-redux' // 修改組件 ReactDom.render( <Provider store={store}> <ReduxApp/> </Provider>, document.getElementById('app') )
完整源碼
import {createStore} from 'redux' import React from 'react' import ReactDom from 'react-dom' import {Provider, connect} from 'react-redux' //reducer const counter = (state = {counter: 0, num: 0}, action) => { switch (action.type) { case ACTION_INCREMENT: return {...state, ...{counter: ++state.counter}} case ACTION_DECREMENT: return {...state, ...{counter: --state.counter}} default: return state } } // action const ACTION_INCREMENT = 'INCREMENT' const ACTION_DECREMENT = 'DECREMENT' // action creator const increment = () => ({ type: ACTION_INCREMENT }) const decrement = () => ({ type: ACTION_DECREMENT }) // store const store = createStore(counter) // react 組件 class App extends React.Component { constructor(props) { super() } render() { const {counter, increment, decrement} = this.props return <div> <p>{counter}</p> <button onClick={increment}>+ </button> <button onClick={decrement}>- </button> </div> } } let ReduxApp = connect( (state) => { return { counter: state.counter } }, (dispatch) => { return { increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), } } )(App) ReactDom.render( <Provider store={store}> <ReduxApp/> </Provider>, document.getElementById('app') )