将React组件注入另一个React组件的最佳方法是什么?或者我应该打扰?

时间:2015-10-08 17:46:22

标签: javascript dependency-injection reactjs

在处理我的第一个大型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')
);

或者我只是把脱钩过度了?我在任何教程或示例中都看不到其他任何人这样做。

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

2 个答案:

答案 0 :(得分:1)

这是一种模式,您不时会看到有必要指定一个组件 type ,它传递给的组件将实例化自己;例如,the React TransitionGroup component takes such a property名为component

  

默认情况下,ReactTransitionGroup呈现为span。您可以通过提供component道具来更改此行为。例如,以下是如何呈现<ul>

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

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

将此模式用于组件的用户指定的内容并不常见,因为this.props.children可以更优雅地解决此问题。

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

有一种常见的分离模式&#34; smart&#34;和&#34;哑巴&#34;组件;哑组件只是简单地呈现他们给出的内容,并且非常容易进行单元测试。智能组件可以获取数据(例如,通过Ajax,或来自磁通存储),组合特定的哑组件,或做出其他的决定,&#34;并且可能更难以测试 - 但同样,由于哑组件已经过测试,理想情况下,您可以检查智能组件的行为是否正确并呈现正确的事物。

要使用您的示例,请Foo 来呈现<div><Bar><Baz /></Bar></div>;它是一个智能组件,测试应该确保它完全呈现。然而,Bar的工作是渲染孩子,并且更容易测试。

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

答案 1 :(得分:0)

结帐mochajs。此测试框架会覆盖import / require,从而解决您的问题。

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