react-redux

145 阅读1分钟

Redux是将整个应用状态存储到到一个地方,称为store 里面保存一棵状态树(state tree) 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件 其它组件可以通过订阅store中的状态(state)来刷新自己的视图.

  1. redux
redux包含三个部分:createStore.js, bindActionCreators, combineReducers.js applyMiddle
createStore: 生成store ==> 暴露出getState() sunscribe() dispatch()方法
bindActionCreators: 用来组合actions
combineReducers:用来搞命名空间的
  1. react-redux
react-redux包含connect,provider
  1. 一个react-redux的例子
app.js ---
import React, { Component } from 'react'
import { render } from 'react-dom'
import Router from './router'
import { Provider } from 'react-redux'
import store from './redux'

render(
  <Provider store={store}>{Router}</Provider>,
  document.querySelector('#root')
)

home.js ---
import React, { Component } from 'react'
import store from '../redux'
import actions from '../redux/actions'
import { connect } from 'react-redux'
class Home extends Component {
  constructor(props) {
    super(props)
  }
  handleClick = () => {
    this.props.increment()
  }
  render() {
    return (
      <div>
        Home
        <p>{this.props.count}</p>
        <button onClick={this.handleClick}>click</button>
      </div>
    )
  }
}
export default connect(
  state => state,
  actions
)(Home)

源码分析

  1. bindActionCreator.js
function bindActionCreators(actions, dispatch) {
  let newActions = {}
  for (let attr in actions) {
    newActions[attr] = function() {
      dispatch(actions[attr].apply(null, arguments))
    }
  }
  return newActions
}

export default bindActionCreators
  1. combineReducers.js
import counter from '../reducer/counter'

export function combineReducers(reducers) {
  return function(state = {}, action) {
    let newState = {}
    for (let attr in reducers) {
      let reducer = reducers[attr]
      newState[attr] = reducer(state[attr], action)
    }
    return newState // 返回的是那个大对象
  }
}

  1. createStore.js
const createStore = reducer => {
  let state
  let getState = () => JSON.parse(JSON.stringify(state))
  let listeners = []
  let dispatch = action => {
    state = reducer(state, action)
    listeners.forEach(l => {
      l()
    })
  }
  let subscribe = listener => {
    listeners.push(listener)
    return () => {
      listeners = listeners.filter(_ => {
        _ !== listener
      })
    }
  }
  dispatch({type: '@@redux/INIT'})
  return {
    getState,
    subscribe,
    dispatch
  }
}

export {createStore}

  1. connect.js
import React, { Component } from 'react'
import propTypes from 'prop-types'
import bindActionCreators from '../redux/bindActionCreators'

export default function(mapStateToProps, mapDispatchToProps) {
  return function(WrapedComponent) {
    class ProxyComponent extends Component {
      static contextTypes = {
        store: propTypes.object
      }
      constructor(props, context) {
        super(props, context)
        this.store = context.store
        this.state = mapStateToProps(this.store.getState())
      }
      componentWillMount() {
        this.unsubscribe = this.store.subscribe(() => {
          this.setState(mapStateToProps(this.store.getState()))
        })
      }
      componentWillUnmount () {
        this.unsubscribe()
      }
      render () {
        let actions = bindActionCreators(mapDispatchToProps, this.store.dispatch)
        return <WrapedComponent {...this.state} {...actions}/>
      }
    }
    return ProxyComponent
  }
}