直接调用功能组件

Est*_*ask 8 javascript reactjs

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

const Foo = props => <Bar />;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

这是一个演示此案例的演示.

这是一种被广泛接受的做法,但它的问题在于无法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);
Run Code Online (Sandbox Code Playgroud)

这样它可以用作:

<ThemedInput ref={inputRef} />
...
inputRef.current.focus();
Run Code Online (Sandbox Code Playgroud)

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

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

mar*_*lin 1

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

无论如何,下面我想介绍另一种使用findDOMNode而不是引用来做到这一点的方法:

我创建了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;
}
Run Code Online (Sandbox Code Playgroud)

// 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'));
Run Code Online (Sandbox Code Playgroud)

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