无状态功能组件只是一个接收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} />;
}
这是一个demo,显示了这种情况。
这是一种被广泛接受的做法,但问题在于无法从无状态函数中获取包装DOM元素的ref
,因此该组件使用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的通常要求。
在上述情况下,它被认为是一种正确的方法吗?
我认为直接调用无状态功能组件没有任何问题。正如你所说,它甚至消除了一个微小的开销。至于可能的含义,可以大胆地说,没有任何影响,将来不会有任何影响,因为这是一种非常罕见的使用SFC的方式。但是一切都指出不应该有任何影响(它只是一个函数调用更少)。
无论如何,下面我想介绍另一种方法,使用findDOMNode
而不是refs:
我已经创建了Focus
组件,它非常方便使用,但需要首先进行初始化(因为我们需要一种方法来触发道具之外的焦点,因为组件可能会使用相同的道具重新渲染):
// 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'));
当您不需要使用任何生命周期方法或不需要更新组件状态时,功能组件非常有用。只要你不需要它们,你就是好的,但最好还是选择无状态组件。
这不会影响性能问题,但会获得有关其性能的利润,因为我们只是简单地使用函数来渲染组件而不关心它的更新,安装,接收道具等。但是使用无状态组件仍然没有100%的收益因为内部反应使用类来渲染它们。
这个post还将指导哪一个在有状态组件和无状态组件之间进行选择。
此外,您不仅可以收到道具,还可以收到参考:
const stateless = (props, ref) => <ReturnComponent {...props} ref={ref} />
好的,让我改进我的陈述。大多数博客甚至文档都指出无状态组件没有引用。以下是针对此问题准备的一些问答:
我是否需要使用有状态组件才能使用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} />
}