【问题标题】:What's the best way to inject a React component into another React component? Or should I bother?将 React 组件注入另一个 React 组件的最佳方法是什么?还是我应该打扰?
【发布时间】:2015-10-08 17:46:21
【问题描述】:

在开发我的第一个大型 React 应用程序时,我开始对嵌套组件的紧密耦合感到不安,尤其是在编写单元测试时。

如果是高级组件,它的渲染函数返回<div><Bar><Baz /></Bar></div>,我希望能够单独测试Foo、Bar和Baz。

我搜索了建议,但没有找到任何建议。所以,我自己想出了两种注入方法:工厂函数和通过外部组件的属性。 (我说的不是儿童。我说的是“内置”依赖项——人们通常通过 require 或 import 语句导入的那种。

属性

const Baz = React.createClass({
  render() {
    return <p>Inner</p>;
  }
});

const Foo = React.createClass({
  render() {
    const Bar = this.props.innerComponent;
    return <Bar />;
  }
});

ReactDOM.render(
  <Foo innerComponent={Baz} />,
  document.getElementById('container')
);

工厂

const Baz = React.createClass({
 render() {
   return <p>Inner</p>;
 }
});

const fooFactory = innerComponent => {
  return  React.createClass({
    render() {
      const Bar = innerComponent;
      return <Bar />;
   }
 });
};

const Foo = fooFactory(Baz);

ReactDOM.render(
  <Foo innerComponent={Baz} />,
  document.getElementById('container')
);

还是我只是把脱钩做得太过分了?在任何教程或示例中,我几乎没有看到其他人这样做。

您是否会倾向于有时注入组件,但有时不会?在什么情况下?而且,如果你这样做了,你会使用上述技术之一还是以其他方式进行?

【问题讨论】:

    标签: javascript dependency-injection reactjs


    【解决方案1】:

    当需要在运行时指定一个组件type时,你会不时看到这种模式,它传递给的组件将实例化自己;比如the React TransitionGroup component takes such a propertycomponent

    默认情况下ReactTransitionGroup 呈现为span。您可以通过提供 component 属性来更改此行为。例如,以下是您将如何呈现 &lt;ul&gt;

    <ReactTransitionGroup component="ul">
      ...
    </ReactTransitionGroup>
    

    React 可以渲染的每个 DOM 组件都可以使用。但是,component 不需要是 DOM 组件。它可以是你想要的任何 React 组件;甚至是你自己写的!只需写component={List},您的组件就会收到this.props.children

    将这种模式用于用户指定的组件的内容不太常见,因为this.props.children 更优雅地解决了这个问题。

    但是,就测试而言,常见的解决方案是简单地将每个组件单独导出并单独测试。如果一个高级组件以某种方式组合它们,那么您真正需要测试的是它们是否正确组合,因为这些组件也是单独测试的。

    有一种区分“智能”和“哑”组件的常见模式;愚蠢的组件只是简单地呈现它们所给出的内容,并且非常容易进行单元测试。智能组件可以获取数据(例如,通过 Ajax 或从通量存储)、组合特定的哑组件或做出其他“决策”,并且可能更难测试——但同样,由于哑组件已经过测试,理想情况下您可以只需检查智能组件的行为是否正确并呈现正确的内容。

    以您的示例为例,渲染&lt;div&gt;&lt;Bar&gt;&lt;Baz /&gt;&lt;/Bar&gt;&lt;/div&gt;Foo工作;它是一个智能组件,测试应该确保它完全呈现。然而,Bar 的工作是渲染它的孩子,并且更容易测试。

    您还可以模拟出组件with TestUtils.mockComponent

    【讨论】:

    • 谢谢。这就说得通了。您通常不会将工厂函数与其正在制作的任何东西解耦,因为它的工作就是制作那个东西。
    • @MarcusGeduld 对。这种依赖倒置有时很有用,但只是过度设计了其他人。
    【解决方案2】:

    查看mochajs。这个测试框架覆盖了import/require,解决了你的问题。

    这确实意味着您的子组件需要编写为 ECMA 6 或 NodeJS 模块,但这实际上只是意味着它们需要位于单独的源文件中。

    【讨论】:

    • 谢谢,这是一个很好的提示。尽管不被特定的测试框架束缚会很好。我认为,一般来说,组件的松散耦合也会很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-10
    • 2020-08-26
    • 1970-01-01
    • 2022-11-21
    • 2020-06-03
    相关资源
    最近更新 更多