Redux:在事件处理程序中使用状态数据执行业务逻辑的最佳方式

时间:2017-03-07 00:17:46

标签: redux redux-thunk

我花了几周的时间研究这个问题并且没有达成共识。我有一个带有事件处理程序的组件。他们需要使用与组件无关的状态数据来执行业务逻辑,并根据该组件和组件数据分派不同的操作。最好的方法是什么?我列出了一些非常简单的例子,这些例子并不完整,但显示了我所谈论的内容的主旨。

方法1:将所有内容传递给组件

我可以轻松传递组件所需的所有内容,包括与其无关的状态数据。容器不需要扩展React.Container。

MyContainer.js

const mapStateToProps = (state) => {
  return ({
    foo: state.my.foo,
    bar: state.other.bar
  })
};

const mapDispatchToProps = (dispatch) => ({
  doSomething: (value) => {
    dispatch(someAction(value));
  }
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(MyComponent);


MyComponent.js

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.onClickHandler = this.onClickHandler.bind(this);
  }

  onClickHandler() {  
    if ( complicated logic with this.props.bar ) {
      this.props.doSomething(this.props.foo);
    }
  }

  render() {
    return (
      <button onClick={this.onClickHandler} />
    )
  }
}

优点: 非常简单。组件需要的所有东西都会传递给它。

CONS: 该组件正在做业务逻辑,这看起来并不正确。但我无法在容器中轻松执行此逻辑,因为它不容易访问不相关的状态数据。

ALTERNATIVE: 我可以将所有这些道具传递到组件的doSomething()中,让容器的doSomething()执行逻辑。但这意味着容器从未使用过一些道具,它们只是通过了。但这会将业务逻辑重新放回容器中。

方法2:让容器扩展React.Component并渲染它需要的道具

我可以用适当的React.Component类定义容器,通过props传递它需要的状态数据,定义一个函数来使用这个状态和本地状态数据,然后渲染它。

class MyContainer extends React.Component {

  constructor(props) {
    super(props);
    this.onClickHandler = this.onClickHandler.bind(this);
  }

  onClickHandler(foo) {
    if ( this.props.bar ) {
      this.props.dispatch(foo)
    }
  }

  render() {
    return (
      <MyComponent onClickHandler={this.onClickHandler} {...this.props} />
    )
  }
}

优点: 业务逻辑可以在容器中发生。

CONS: 很多仪式。容器必须传递其业务逻辑功能所需的任何状态数据。

方法3:导出connect()

时使用mergeProps

我还没试过这个。但是connect()的第三个参数公开了mapState和mapDispatch的结果,因此您可以生成依赖于mapState数据的函数。

我甚至没有试过这个,因为Dan Abramov暗示它并不好,并且可能会对性能产生影响。

方法4:使用thunk和getSate()

只需传递组件所需的任何数据。调度一个使用getState()来查看业务逻辑所需的状态数据的函数。然后它可以发送任何最终行动。

MyReducer.js

export function actionDecider(foo) {
  return (dispatch, getState) => {
    const state = getState();
    if ( complicated logic with state.other.bar ) {
      dispatch(someAction(foo));
    }
  };
}


MyContainer.js

const mapStateToProps = (state) => {
  return ({
    foo: state.my.foo
  })
};

const mapDispatchToProps = (dispatch) => ({
  doSomething: (value) => {
    dispatch(actionDecider(value));
  }
})

export default connect(
  mapStateToProps,
  (dispatch) => ({
    ...mapDispatchToProps(dispatch)
  })
)(MyComponent);


MyComponent.js

class MyComponent extends React.Component {

  constructor(props) {
    super(props);
    this.onClickHandler = this.onClickHandler.bind(this);
  }

  onClickHandler() {  
    this.props.doSomething(this.props.foo);
  }

  render() {
    return (
      <button onClick={this.onClickHandler} />
    )
  }
}

优点: 更少的代码。很容易掌握。无需将状态数据填充到奇怪的区域,只需在需要时访问它。

CONS: 关于这是否是反模式的意见分歧。甚至丹·阿布拉莫夫也表达了一些反对意见,尽管有人说这是过分夸大其词。巨大的州树存在性能问题吗?

就个人而言,我喜欢在方法4中使用thunk。虽然我也可以看到方法1上的替代方法。有正确的方法吗?有错误的方法吗?

0 个答案:

没有答案