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

Redux:使用事件处理程序中的状态数据执行业务逻辑的最佳方法,redux,redux-thunk,Redux,Redux Thunk,我花了几个星期研究这个问题,但没有达成共识。我有一个带有事件处理程序的组件。他们需要使用与组件无关的状态数据来执行业务逻辑,并基于该状态数据和组件数据分派不同的操作。最好的方法是什么?我列出了一些非常简单的例子,这些例子并不完整,但说明了我所说的要点 方法1:将所有内容传递给组件 我可以轻松地将所需的所有信息传递给组件,包括与组件无关的状态数据。容器不需要扩展React.container MyContainer.js const mapStateToProps = (state) =>

我花了几个星期研究这个问题,但没有达成共识。我有一个带有事件处理程序的组件。他们需要使用与组件无关的状态数据来执行业务逻辑,并基于该状态数据和组件数据分派不同的操作。最好的方法是什么?我列出了一些非常简单的例子,这些例子并不完整,但说明了我所说的要点

方法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} />
    )
  }
}
MyContainer.js
常量mapStateToProps=(状态)=>{
返回({
foo:state.my.foo,
酒吧:state.other.bar
})
};
const mapDispatchToProps=(调度)=>({
doSomething:(值)=>{
分派(动作(值));
}
})
导出默认连接(
MapStateTops,
mapDispatchToProps
)(MyComponent);
MyComponent.js
类MyComponent扩展了React.Component{
建造师(道具){
超级(道具);
this.onClickHandler=this.onClickHandler.bind(this);
}
onClickHandler(){
if(使用this.props.bar的复杂逻辑){
this.props.doSomething(this.props.foo);
}
}
render(){
返回(
)
}
}
优点: 很简单。组件所需的一切都传递给它

缺点: 组件正在执行业务逻辑,这似乎不正确。但我无法在容器中轻松执行此逻辑,因为它不容易访问无关的状态数据

备选方案: 我可以将所有这些道具传递到组件的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} />
    )
  }
}
class MyContainer.Component{
建造师(道具){
超级(道具);
this.onClickHandler=this.onClickHandler.bind(this);
}
onClickHandler(foo){
如果(this.props.bar){
此.props.dispatch(foo)
}
}
render(){
返回(
)
}
}
优点: 业务逻辑可以发生在容器中

缺点: 很多仪式。必须向容器传递其业务逻辑函数所需的任何状态数据

方法3:导出connect()时使用mergeProps 我还没试过这个。但是connect()的第三个参数公开了mapState和mapDispatch的结果,因此您可以生成依赖mapState数据的函数

我甚至没有尝试过这一次,因为丹·阿布拉莫夫暗示这不是很好,可能会对性能产生影响

方法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} />
    )
  }
}
MyReducer.js
导出函数actionDecider(foo){
返回(调度,获取状态)=>{
const state=getState();
if(带state.other.bar的复杂逻辑){
调度(someAction(foo));
}
};
}
MyContainer.js
常量mapStateToProps=(状态)=>{
返回({
foo:state.my.foo
})
};
const mapDispatchToProps=(调度)=>({
doSomething:(值)=>{
派遣(行动决策者(价值));
}
})
导出默认连接(
MapStateTops,
(调度)=>({
…mapDispatchToProps(调度)
})
)(MyComponent);
MyComponent.js
类MyComponent扩展了React.Component{
建造师(道具){
超级(道具);
this.onClickHandler=this.onClickHandler.bind(this);
}
onClickHandler(){
this.props.doSomething(this.props.foo);
}
render(){
返回(
)
}
}
优点: 更少的代码。很容易掌握。不需要将状态数据塞进奇怪的区域,只需要在需要时访问它

缺点: 关于这是否是一种反模式的意见相左。即使是丹·阿布拉莫夫也表达了一些反对意见,尽管有人说这是夸大其词。大型状态树是否存在性能问题


就个人而言,我喜欢在方法4中使用thunk。尽管我可以看到方法1的替代方案也能起作用。有正确的方法吗?有错误的方法吗?

有相关的主题是的,我在发帖前通读了所有这些。这表明thunks可以使用。但这只是众说纷纭中的一篇文章。这似乎是许多项目在某个时候遇到的一个常见问题,因此我们希望社区能够帮助区分正确与错误的方式。嗯,我是Redux的维护者之一,所以我想我有一些可信度:)(是的,我在那篇文章中反对的观点之一是丹·阿布拉莫夫,Redux的创建者,但这是我认为他有点错的地方之一).你可能想读我的另一篇相关文章,.哦,我不知道你是维护者之一。很抱歉,我不是有意淡化你的观点。知道你是维护者会有很大帮助。我的团队已经开始撤销彼此的工作,因为他们从不同的来源听到了不同的事情。因此,让像你这样的人给f反馈说thunks中的业务逻辑是好的,这非常有帮助。非常感谢!当然:)FWIW,我刚刚写了两篇帖子,讨论了Redux背后的历史和意图,以及为什么存在常见的实践,你可能会发现这些都很有帮助,而且信息丰富。还有一个相关的话题是的,我在发布之前通读了所有这些。这表明thunks可以使用。但这只是一个不同的海洋中的一篇文章