React:将简单的逻辑放在 Container 或 Presentational 组件中?

React: To put simple logic in Container or Presentational component?

我有一个容器组件,它将对象数组向下传递到表示组件以进行输出。

在演示组件中,我需要显示满足特定条件的这些对象的数量。最好的做法是在容器组件中执行计数并将其传递给展示组件,还是在展示组件中执行此计数。

即:

export class ResultsPage extends React.Component {

  constructor(props){
    super(props);
  }

  countSexyObjects(){
    const matching = this.props.allObjects.filter((obj)=>{
      return obj.sexy === true;
    });

    return matching.length
  }

  render(){
    return (
        <PresentationalComponent  allObjects={this.props.allObjects}
                                  numberOfSexyObjects={this.countSexyObjects()} />
    );
  }
}


let PresentationalComponent = (props) => {

  return (
    <div>
      There are {props.numberOfSexyObjects} sexy objects
    </div>
  );
};

export class ResultsPage extends React.Component {

  constructor(props){
    super(props);
  }

  render(){
    return (
        <PresentationalComponent allObjects={this.props.allObjects} />
    );
  }
}


let PresentationalComponent = (props) => {

  const countSexyObjects = () => {
    const matching = this.props.allObjects.filter((obj)=>{
          return obj.sexy === true;
        });

    return matching.length
  };

  return (
    <div>
      There are {countSexyObjects()} sexy objects
    </div>
  );
};

出于以下几个原因,我会使用第一种格式:

  • 智能组件应该更好地理解 "SexyObject" 是什么。如果它是对象中的一个字段,那很简单,可以用任何一种方式争论。如果它依赖于 Web 服务或一些更复杂的逻辑来确定它是否性感,那么您永远不会希望在表示层中使用它。简单有一种变复杂的方式,所以我最初会使用支持复杂性的结构。

  • 使用智能组件中的逻辑测试代码会更简单。您可以启动组件,然后检查固定数据集中的输出变量。

  • 如果 "SexyObject" 的标准可以由组件更改,如果您将选择逻辑分开,您将保留重用您的展示组件的能力。

只要我的 0.02 美元

理想状态在 React 中被认为是一种邪恶。我知道 React 是建立在状态的概念之上的,但是状态越少越好,这意味着尝试使用本质上纯的函数来构建代码。

恕我直言,您的第一个示例更正确。 ResultsPage 是您的容器组件(智能组件),而另一个是愚蠢的。 Dumb 组件不管理状态,只负责 UI 的外观。您可以将所有 html、bootstrap 逻辑放在那里。

这个模式之所以好,是因为现在假设你想从 XHR 调用中获取匹配条件,在第二种情况下你的代码将是

export class ResultsPage extends React.Component {

  constructor(props){
    super(props);
  }

  getSexyMatcher() {
    /* make ajax call here */
    return results;
  }

  render(){
    return (
        <PresentationalComponent allObjects={this.props.allObjects} sexyMatcher={getSexyMatcher()}/>
    );
  }
}


let PresentationalComponent = (props) => {

  const countSexyObjects = () => {
    const matching = this.props.allObjects.filter((obj)=>{
          return obj.sexy.match(props.sexyMatcher)
          // return obj.sexy === true;
        });

    return matching.length
  };

  return (
    <div>
      There are {countSexyObjects()} sexy objects
    </div>
  );
};

注意到您是如何为相同的业务逻辑更改两个组件的吗?更糟糕的是,如果其他人在代码库的其他地方使用了 PresentationalComponent 怎么办? 在第一种情况下,事情要简单得多。只需在智能组件中添加 ajax 函数并将结果传递给 UI 组件即可。