什么归类为 React 功能组件?

IT技术 javascript reactjs
2021-05-16 21:23:14

我正在关注 Udemy 的教程,其中讲师试图解释 HOC。

为了解释 HOC,他创建了一个具有功能组件的函数(至少他是这么说的)。这是代码:

const withClass = (WrappedComponent, className) => {
     return (props) => (
         <div className={className}>
             <WrappedComponent {...props} />        
     </div>

   )
 }

React 文档显示了这个例子:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

并提到:

这个函数是一个有效的 React 组件,因为它接受一个带有数据的“props”(代表属性)对象参数并返回一个 React 元素。我们称这些组件为“函数式”,因为它们实际上就是 JavaScript 函数。

[问题]

简单来说,可以这样说:任何以 props 作为参数的函数都可以归类为函数式组件吗?如果没有,有人可以简要解释一下 React 中的功能组件吗?

4个回答

任何以 props 作为参数的函数都可以归类为函数组件?

不, props 只是函数参数,就像所有其他普通函数参数一样。因此,如果我们定义任何接受参数的函数,它不一定是 React 功能组件,就像这不是 React 组件:

const Testing = props => {
   const a = 10;
   return a * props.a;
}

重要的部分是“如果该组件返回一个 React 元素”,那么它才会是一个 React 功能组件。

为了更清楚,只需在单独的文件中定义以下函数;转译时不会抛出任何错误:

const Test = props => props.key * 10;

但是如果你在一个单独的文件中定义这个下面的组件而不导入 React,它会抛出错误,React 未定义,当你转译时:

const Test = props => <div>{props.key * 10}</div>;

因为JSX将被转换成React.createElement(....)并且需要 React。上述组件转换版本将是:

var Test = function Test(props) {
  return React.createElement(
    "div",
    null,
    props.key * 10
  );
};

我会建议,使用Babel REPL并定义两个函数并检查输出。

当您创建这样的函数时:

function MyComponent() {
  return null;
}

它是一个普通的 JavaScript 函数,不是吗?但它可以变成一个 React 组件。如果您使用react-preset允许您使用 JSX 语法,您可以将此函数转换为呈现 null 的组件:

<Welcome /> 

将产生:

React.createElement(MyComponent, null);

因此,函数式组件是从函数而不是通过扩展 React 基类 ( React.Component)创建的组件

这只是定义它们的两种方法。您可以使用Babel 在线转译器玩转并查看幕后的内容

是的,以 props 作为参数的函数可以归类为功能性无状态react组件。

这个函数应该返回一个有效的组件答案;例如,React 节点、数组、数字、字符串或空值。

这样的函数没有状态,你不能用它设置组件生命周期方法。

您的 JSX 代码被转换为 React.createElement 函数,该函数接收“原生”组件,例如 div、span 或函数。

为了澄清我的答案,我将包括最简单的 React.createElement 实现(Dan Abramov 前段时间在 JS Bin 上发布了此代码):

// Necessary for JSX to work
window.React = {
  createElement(type, props, ...children) {
    return {
      type,
      props: {
        ...props,
        children: children || props.children
      }
    }
  }
};

// What kind of node are we dealing with?
function getNodeKind(node) {
  if (node === false || node == null) {
    // A hole: false, null, undefined
    return 'EMPTY';
  }
  if (typeof node === 'string' || typeof node === 'number') {
    // Text or number: 'Hello', 42
    return 'TEXT';
  }
  if (Array.isArray(node)) {
    // An array of nodes!
    return 'ARRAY';
  }
  if (typeof node.type === 'string') {
    // An element describing “host” (e.g. DOM) component: <div />
    return 'HOST';
  }
  if (typeof node.type === 'function') {
    // An element describing “composite” (user-defined) component: <Foo />
    return 'COMPOSITE';
  }
  throw new Error('Weird node: ' + node);
}

// To render a host element like <div />, we’ll generate
// its tag markup and render children inside.
// This is a simple implementation and doesn’t attempt to escape anything.
function renderHostElementToString(el) {
  // Separate children from attributes
  const { children, ...otherProps } = el.props;

  // Create an attribute string for markup
  let attributes = Object.keys(el.props)
    .map(propName => propName + '=' + el.props[propName])
    .join(' ');
  
  // If attributes exist, prepend a space to separate from tag
  if (attributes) {
    attributes = ' ' + attributes;
  }
  
  // Create tag strings for markup
  // For host elements, type is the tag name
  const openingTag = '<' + el.type + attributes + '>';
  const closingTag ='</' + el.type + '>';
  
  return (
    openingTag +
    // Render children recursively!
    renderToString(children) +
    closingTag
  );
}

// To render a composite component like <Foo />,
// we’ll call its type (`Foo`) with its props.
// We will then recursively render it.
function renderCompositeElementToString(el) {
  const renderedEl = el.type(el.props);
  return renderToString(renderedEl);
}

// Handle different types differently.
function renderToString(node) {
  var kind = getNodeKind(node);
  switch (kind) {
    case 'EMPTY':
      return '';
    case 'TEXT':
      return node.toString();
    case 'ARRAY':
      // Render each of them
      return node.map(renderToString).join('');
    case 'HOST':
      // <div />
      return renderHostElementToString(node);
    case 'COMPOSITE':
      // <Foo />
      return renderCompositeElementToString(node);
  }
}

// Let’s give it a try!

function Badge({ children }) {
  return (
    <div>
      <hr />
      {children}
      <hr />
    </div>
  );
}

function UserInfo({ name, location }) {
  return (
    <Badge>
      {name} lives in {location}.
    </Badge>
  );
}

function App() {
  return (
    <div>
      <h1>
        Hello, React!
      </h1>
      <UserInfo
        name="Dan"
        location="London"
      />
    </div>
  );
}

document.body.innerHTML = renderToString(<App />);

React 中的一个函数式组件:

  • 用于展示静态数据
  • 无法处理获取数据
  • 容易写

例子:

const Header = () => {
  return <Text>Hello World!</Text>
}