hacker0limbo / my-blog

个人博客
5 stars 1 forks source link

redux 中 dispatch 一个 action 的几种写法 #2

Open hacker0limbo opened 5 years ago

hacker0limbo commented 5 years ago

以下代码均以计数器为例.

方法一

connect方法不加第二个参数, 默认会将dispatch传入至组件的props

// drecement 是一个 action creator
const decrement = (id) => {
  return {
    type: "DECREMENT",
    id
  }
}

const App = props => {
  const { counter, dispatch } = props

  return (
    <div>
      <span></span>
      <button onClick={() => dispatch({ type: "INCREMENT" })}></button>
      <button onClick={() => dispatch(decrement(1))}></button>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

export default connect(mapStateToProps)(App)

方法二

使用mapDispatchToProps, 此时dispatch方法不会再被传入到组件的props中, 取而代之的传入的是一个对象(类似mapStateToProps), 对象里面包含所有可以 dispatch一个action的函数

// drecement 是一个 action creator
const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}

const App = props => {
  const { counter, increment, decrement } = props

  return (
    <div>
      <span></span>
      <button onClick={() => increment()}></button>
      <button onClick={() => decrement(1)}></button>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

const mapDispatchToProps = dispatch => {
  return {
    increment: () => dispatch({ type: "INCREMENT" }),
    decrement: (id) => dispatch(decrement(id))
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

方法三

使用bindAcionCreator, 相比方法二, 无需编写一系列函数.

注意, 需要将action写成action creator形式, 即函数形式

import { bindAcionCreator } from 'redux'

const increment = () => {
  return {
    type: "INCREMENT",
  }
}

// drecement 是一个 action creator
const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}

const App = props => {
  const { counter, increment, decrement } = props

  return (
    <div>
      <span></span>
      <button onClick={() => increment()}></button>
      <button onClick={() => decrement(1)}></button>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

const mapDispatchToProps = dispatch => {
  return bindActionCreator({ increment, decrement }, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

方法四(推荐)

mapDispatchToProps定义为一个对象

const increment = () => {
  return {
    type: "INCREMENT",
    id
  }
}

// drecement 是一个 action creator
const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}

const App = props => {
  const { counter, increment, decrement } = props

  return (
    <div>
      <span></span>
      <button onClick={() => increment()}></button>
      <button onClick={() => decrement(1)}></button>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

export default connect(mapStateToProps, { increment, decrement })(App)

方法五(推荐)

方法四存在的问题是, 如果有很多action creator, 那么写起来不会很方便, 此时结合方法三里的bindAcionCreator可以一次性导入

稍微提一下bindAcionCreator, 接受两个参数:

  1. 一个函数(一个 action creator), 或者一个对象, 每个元素对应一个action creator
  2. dispatch
// actions.js

export const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}

// drecement 是一个 action creator
export const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}
import { bindAcionCreator } from 'redux'
import * as types from './actions'

const App = props => {
  const { counter, increment, decrement } = props

  return (
    <div>
      <span></span>
      <button onClick={() => increment()}></button>
      <button onClick={() => decrement(1)}></button>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

const mapDispatchToProps = dispatch => {
  return bindActionCreator(types, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

方法六

在方法五的基础上, 使用装饰器@connect, 此方法需要开启babel

// actions.js

export const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}

// drecement 是一个 action creator
export const decrement = id => {
  return {
    type: "DECREMENT",
    id
  }
}
import { bindAcionCreator } from 'redux'
import * as types from './actions'

const mapStateToProps = state => {
  return {
    counter: state.counter
  }
}

const mapDispatchToProps = dispatch => {
  return bindAcionCreator(types, dispatch)
}

@connect(mapStateToProps, mapDispatchToProps)
class App extends Component {
  render() {
    const { counter, increment, decrement } = this.props

    return (
      <div>
        <span></span>
        <button onClick={() => increment()}></button>
        <button onClick={() => decrement(1)}></button>
      </div>
    )
  }
}

总结

自己常用的主要是 4 和 5. 当然肯定是存在别的更加优雅的写法, 也欢迎在评论里和我交流

参考