【问题标题】:React: Is it bad practice to import a child component directly rather than pass in as a dependency?React:直接导入子组件而不是作为依赖项传入是不好的做法吗?
【发布时间】:2018-07-01 08:48:25
【问题描述】:

我可能想多了,但我很好奇直接导入子组件是否在耦合和测试方面是不好的做法。

下面是一个简单的例子:

import Header from './header.jsx';

class Widget extends React.Component {
    render() {
        return (
            <div>
                <Header></Header>
                <div>{this.props.importantContent}</div>
            </div>
        )
    }
}

在我看来,WidgetHeader 之间现在存在耦合。关于测试,在测试Widget 组件时,我看不到模拟Header 组件的简单方法。

其他较大的 React 应用程序如何处理这样的情况?我应该将Header 作为道具传递吗?如果使用react-redux,我可以使用下面的Connect 方法注入标头以减少样板。有声音吗?

import { connect } from 'react-redux';
import Header from './header.jsx';

class Widget extends React.Component {
    render() {
        return (
            <div>
                {this.props.header}
                <div>{this.props.importantContent}</div>
            </div>
        )
    }
}

const mapStateToProps = state => {
  return {
    header: Header
  }
}

export default connect(mapStateToProps)(Widget)

我感兴趣的是做社区通常在做的事情。我看到一种解决方案是使用 Enzyme 之类的东西对组件的主要部分而不是子组件进行浅层渲染。

想法或其他想法?

【问题讨论】:

  • 我不认为“这很糟糕”。这肯定不是最佳实践,因为它降低了代码的可读性,从而使其更难维护。在这两种情况下,您都可以保持小部件的依赖项具有标题组件。我不知道其他大型应用程序,但我从未见过有人以这种方式使用它。
  • 好主意,但我认为可能有点离题。在这两种情况下,您仍然拥有Header 依赖关系。第二个例子也是更多样板,而不是更少。除非您的组件需要能够显示不同的标题,否则将其作为我能想到的 prop 传递没有任何好处。
  • 您的第二个代码块示例很奇怪。如果您想通过道具传递组件,那么就这样做。然后,无论您在代码中实际使用小部件的任何位置,都可以在其中传递 Header &lt;Widget header={Header} /&gt; 如果未提供默认 Header,您始终可以使用默认 Header

标签: reactjs testing react-redux enzyme


【解决方案1】:

只要组件总是渲染相同的东西,它就可以直接渲染为子组件而不是父组件。

如果组件的所有其他部分保持不变,并且只有 Header 可以在页面之间有所不同,那么您实际上可以将其作为 HOC 来实现,而不是将其作为 props 传递

const MyCompFactory = ({CustomHeader = DefaultHeader}) => {
  return class Widget extends React.Component {

        render() {
            return (
                <div>
                    <CustomHeader/>
                    <div>{this.props.importantContent}</div>
                </div>
            )
        }
    }

}

并像使用它一样

const CustomComponent = MyCompFactory({CustomComponent: Header})

只要在您的情况下进行测试,您可以只对组件进行浅层渲染,然后搜索 Header 组件是否呈现类似的东西

import Header from 'path/to/header'

const component = shallow(
    <Widget {...customProps}/>
)

test('test' , () => {
   expect(component.find(Header).exists()).toBe(true)
})

【讨论】:

    【解决方案2】:

    将元素/组件作为道具传递是个好主意。拥有默认道具也是一个好主意:

    const Widget = ({
      header = <div>Default Header.. </div>,
      content = <div>Default Content.. </div> 
    }) =>
      <div>
        {header}
        {content}
      </div>
    

    然后在您的应用中的其他地方:

    <Widget header={<Header title="Foo" />} content="content from props" />
    

    无需使用connect注入

    如果你想与 props 交互/将数据发送回父级,你也可以传递一个组件,而不仅仅是一个元素:

    const Widget = ({
      Header = props => <div>Default Header.. </div>,
      Content = props => <div>Default Content.. </div> 
    }) =>
      <div>
        <Header />
        <Content />
      </div>
    

    其他地方:

    <Widget Header={Header} Content={props => <Content />} />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-07
      • 2018-07-01
      • 2021-08-29
      • 2020-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多