使用 redux 一般使用 redux 和 react-redux

  • redux 提供 action、reducer、store
  • react-redux 负责提供 Provider、connect
    1. npm install --save redux
    2. npm install --save react-redux

案例

2.gif

代码结构:

  1. src
  2. |_ index.js
  3. |_ redux
  4. |_ action-types.js
  5. |_ actions.js
  6. |_ reducers.js
  7. |_ store.js
  8. |_ pages
  9. |_ CounterPanel.js
  10. |_ CounterItem.js

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import CounterPanel from './pages/CounterPanel'
import store from './redux/store'
import {Provider} from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    {
      console.log('index.js:', store.getState())
    }
    <CounterPanel />
  </Provider>
, document.querySelector('#root')

action-types.js

export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

actions.js

/**
 * action creator 返回的是 action
 */
import * as ActionTypes from './action-types'

export const increment = (caption) => ({
  type: ActionTypes.INCREMENT,
  caption
})

export const decrement = (caption) => ({
  type: ActionTypes.DECREMENT,
  caption
})

reducers.js

import * as ActionTypes from './action-types'

export default (state, action) => {
  console.log('reducers.js', state)
  const {caption} = action

  switch (action.type) {
    case ActionTypes.INCREMENT:
      console.log('reducers.js', action)
      return {...state, [caption]: state[caption]+1}
    case ActionTypes.DECREMENT:
      return {...state, [caption]: state[caption]-1}
    default:
      return state
  }
}

store.js

import {createStore} from 'redux'
import reducer from './reducers'
const initState = {
  'first': 0,
  'second': 2,
  'third': 5
}
const store = createStore(reducer, initState)
console.log('store.js:', store.getState())

export default store

CounterItem.js

import React, {Component} from 'react'
import {connect} from 'react-redux'
import PropTypes from 'prop-types'
import * as Actions from '../redux/actions'

class CounterItem extends Component {
  static propTypes = {
    caption: PropTypes.string.isRequired
  }

  render () {
    return (
      <div>
        <button onClick={this.props.increment}>+</button>
        <button onClick={this.props.decrement}>-</button>
        <span>计数:{this.props.count}</span>
      </div>
    )
  }
}


/**
 * 
 * @param {*} state 是 redux 维护的对象
 * @param {*} ownProps 是 父组件 传递过来的 props
 */
const mapStateToProps = function (state, ownProps) {
  console.log(ownProps)
  console.log(state)
  return {
    count: state[ownProps.caption]
  }
} 

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    increment: () => {
      dispatch(Actions.increment(ownProps.caption))
    },
    decrement: () => {
      dispatch(Actions.decrement(ownProps.caption))
    }
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(CounterItem)

CounterPanel.js

import React, {Component} from 'react'
import {connect} from 'react-redux'
import CounterItem from './CounterItem'
class CounterPanel extends Component {
  render () {

    return (
      <div>
        <CounterItem caption='first' />
        <CounterItem caption='second' />
        <CounterItem caption='third' />
      </div>
    )
  }
}
const mapSatesToProps = (state) => {
  console.log(state) 
  return {}
}
export default connect(mapSatesToProps)(CounterPanel)