直接调用功能组件

IT技术 javascript reactjs
2021-04-10 07:14:06

无状态功能组件只是一个接收props和返回 React 元素的函数

const Foo = props => <Bar />;

可以省略父组件中的这种方式<Foo {...props} />(即React.createElement(Foo, props))以支持Foo直接调用Foo(props),因此React.createElement可以消除微小的开销,但这不是必需的。

直接用props参数调用功能组件是否被认为是一种不好的做法,为什么?这样做有什么可能的影响?这会以负面方式影响性能吗?

我的具体情况是有一些组件对 DOM 元素进行了浅层包装,因为第三方认为这是一个好主意:

function ThirdPartyThemedInput({style, ...props}) {
  return <input style={{color: 'red', ...style}} {...props} />;
}

这是一个演示此案例演示

这是被广泛接受的做法,但它的问题在于无法ref从无状态函数中获取包装的 DOM 元素,因此组件使用React.forwardRef

function withRef(SFC) {
  return React.forwardRef((props, ref) => SFC({ref, ...props}));
  // this won't work
  // React.forwardRef((props, ref) => <SFC ref={ref} {...props } />);
}

const ThemedInput = withRef(ThirdPartyThemedInput);

这样它可以用作:

<ThemedInput ref={inputRef} />
...
inputRef.current.focus();

我知道的明显缺点是withRef需要开发人员了解包装组件的实现,这不是 HOC 的通常要求。

在上述情况下,它被认为是一种正确的方法吗?

2个回答

我不认为直接调用无状态功能组件有什么问题。正如你所说,它甚至消除了一个微小的开销。至于可能的影响,可以大胆地说没有影响,将来也不会有影响,因为这是使用证监会的一种非常罕见的方式。但一切都表明不应该有任何影响的结论(这只是少了一个函数调用)。

无论如何,下面我想提出另一种使用findDOMNode而不是 refs 的方法:

我创建Focus了一个使用起来非常方便但需要先初始化的组件(因为我们需要一种在 props 之外触发焦点的方法,因为一个组件可能会使用相同的 props 重新渲染):

// focus.js
import React from "react";
import { findDOMNode } from "react-dom";

export default function createFocus() {
  class Focus extends React.Component {
    componentDidMount() {
      Focus.now = () => {
        findDOMNode(this).focus();
      }
    }
    render() {
      return this.props.children;
    }
  }

  return Focus;
}

// index.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import createFocus from './focus';

const Focus = createFocus();

import { ThirdPartyThemedInput } from './third-party-lib';

function App() {
  return (
    <div>
      <button onClick={() => Focus.now()}>Proceed with form</button>
      <Focus>
        <ThirdPartyThemedInput placeholder="Fill me" />
      </Focus>
    </div>
  );
}

render(<App />, document.getElementById('root'));

直播地址:https : //stackblitz.com/edit/react-bpqicw

@epsilon 好吧,我希望新版本会带来更好的工具来解决此类问题。
2021-05-26 07:14:06
谢谢你的例子,是的,我想像 Focus 这样使用 findDOMNode 的容器是我们这里唯一的选择。
2021-05-28 07:14:06
findDOMNode 在 16.6 中已弃用
2021-06-01 07:14:06
@epsilon 不完全findDOMNode是,在严格模式下已弃用findDOMNode尽管此方法是一种逃生方法,但没有计划从 react 中移除,并且只有在没有其他选择的情况下才应使用它。
2021-06-06 07:14:06
@marzelin 和即将到来的ConcurrentMode(因此在 内createRoot)取消了在该模式下使用 IMO 的资格,因为它增加了很多噪音。
2021-06-17 07:14:06

当您不需要使用任何生命周期方法或不需要更新组件状态时,功能组件非常有用。就您不需要它们而言,您很好,但最好使用无状态组件。

这不会影响性能问题,但会获得有关其性能的利润,因为我们只是简单地使用函数来渲染组件,而不关心它的更新、挂载、接收props等。但是使用无状态组件仍然没有 100% 的收益因为react内部使用类来呈现它们。

大约有 45% 的改进。

这篇文章还将指导在有状态组件和无状态组件之间选择哪一个。


此外,您不仅可以收到props,还可以收到参考:

const stateless = (props, ref) => <ReturnComponent {...props} ref={ref} />

好的,让我完善一下我的陈述。大多数博客甚至文档都指出无状态组件没有 ref。以下是针对此问题准备的一些问答:

我是否需要使用 statefull 组件才能使用 ref?

不。我已经提到如果我们必须使用组件状态或挂钩某些生命周期方法,我们必须要求基于类的组件。

如何在无状态组件中创建 ref?

const stateless = () => {

  // we can't do this.myRef = React.createRef()
  // so, let's create an object
  const RefObj = {}

  // now, create ref in {RefObj}
  RefObj.myRef = React.createRef()

  return <input type="text" ref={myRef} />
}
我试图帮助你,但我的头脑似乎对你的确切问题没有明确的概念。我可能需要一些新鲜空气一段时间。如果更新后的帖子的场景不是您想要的,稍后会回来。
2021-05-27 07:14:06
感谢您的回答,但是,答案引用了这篇文章作为评论中已经提到的文章,问题在于它是为 React 15 编写的。如果您有关于无状态组件在 16 中如何执行的信息,这会很有帮助。问题不在于有状态与无状态,因此链接不相关。
2021-05-28 07:14:06
问题是这const stateless = (props, ref) => <ReturnComponent {...props} ref={ref} />行不通。无状态组件没有ref第二个参数,这就是forwardRef它的用途。ReturnComponent无状态组件不能接受refprop,因为它们没有 refs,这就是问题中描述的问题的来源(请参阅问题中的“这不起作用”部分)。
2021-06-08 07:14:06
对不起,但我不能太清楚地理解你的问题(也许是因为我要失业了),但如果它可能有帮助:stackoverflow.com/a/52211571/2138752
2021-06-09 07:14:06
感谢您尝试提供帮助。我用我当前案例的可行演示更新了这个问题。关键是无法修改无状态组件以从中获取 <input> ref,我需要以某种方式在它之外获取 ref,这就是将组件作为函数调用的帮助。这不是问题的唯一要点,只是应该很好地使用这种方法的一个例子。
2021-06-15 07:14:06