【问题标题】:What is the difference between function and functional React component?函数和函数式 React 组件有什么区别?
【发布时间】:2022-03-26 15:08:51
【问题描述】:

这不是针对行为,而是针对语法。

两者的语法是相同的,我可以很好地创建一个随机函数,它接受一个名为 props 的参数,但 React 会接受它并用那个函数做它的虚拟 DOM 吗?或者它可能正在检查该函数是否返回 JSX ,但是这个检查什么时候发生?

由于 react 只是一个库,什么时候会静态区分哪个函数是组件,哪个函数不是?

任何对文档的参考都会有所帮助。

【问题讨论】:

  • 虽然我没有具体解决您的问题,但my answer about defining components inside components 中的信息对我们在 React 中看到的一些不同函数类型提供了一些有见地的信息。
  • 它的要点是:一个函数可以被设计成一个组件,但并不是每个返回 JSX 的函数都必须(意味着)一个组件。
  • React 不决定将哪个函数用作组件,您明确将其用作组件(如<FunctionName />)然后 react 渲染它。如果您的功能不符合功能组件的设计,它将无法工作并会显示错误。
  • 当您决定通过在 JSX 中调用函数来将其用作组件时,就会发生区别:<MyFunction />,无论其参数如何,它都等效于 React.createElement(MyFunction)

标签: javascript reactjs


【解决方案1】:

React 不会做任何静态分析来确定一个函数是否是一个组件。

相反,React 会做 “这是虚拟 DOM 的事情” (以及所有其他魔法,如 lifecycles 如果函数返回一个有效的 React 元素

React 抛出一个错误,函数不返回 React 元素。

https://reactjs.org/docs/components-and-props.html:

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

更详细...

从技术上讲,React 根本不需要任何函数或类组件。

使用函数

考虑这个例子,没有任何组件或功能:

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  React.createElement( 'div', null, [
      React.createElement( 'h1', null, 'React without any functions' ),
      React.createElement( 'p', null, 'Technically you don\'t need to pass functions to React.' ),
  ]),
  document.getElementById('root')
);

这很快就会变得很麻烦。

因此,人们可能会想到通过使用将代码分成“部分” 返回这些部分的函数,例如:

const Headline = function(){
  return React.createElement( 'h1', null, 'React with "factory functions"' );
};

const Content = function(){
  return React.createElement( 'p', null, 'You might want to separate stuff using functions.' );
};

const Page = function(){
  return React.createElement( 'div', null, [
    Headline(),
    Content()
  ]);
};

ReactDOM.render(
  Page(),
  document.getElementById('root')
);

请注意,这些只是普通的 javascript 函数,根本没有“魔法”。

如果你的函数没有返回一个有效的 ReactElement,那么 React 只会抛出一个错误,例如:

const Page = function(){
  return { notAValidReactElement: 'this is not a valid react element' };
};

ReactDOM.render(
  Page(),  // ---> Uncaught Error: Objects are not valid as a React child ...
  document.getElementById('root')
);

反应“组件”类型

但这不是最优的,例如所有.createElement() 方法仍然总是同时执行。

React 的人也有类似的想法,所以 React 接受一个函数名 作为 type 参数(而不是例如 'h1'),并像回调一样使用该函数,以便 React 可以决定例如如果函数 实际需要执行,也可以跳过:

const Page = function(){
  return React.createElement( 'div', null, [
    React.createElement( Headline, null, [] ),
    React.createElement( Content, null, [] ) 
  ]);
}

这些仍然是和以前一样的功能。它们之所以起作用,是因为我们编写它们是为了让它们返回正确的值。

这实际上或多或少是关于这个主题的完整故事,但人们也可能对我为什么会感到困惑 谈论React.createElement( Page, ...,而我们通常使用<Page>...之类的东西。

所以...

JSX

有人可能会想到将React.createElement 缩短一点,以减少打字,例如:

const CE = function( type, props, childs ){
  return React.createElement( type, props, childs );
};

ReactDOM.render(
  CE( 'div', null, [
      CE( 'h1', null, 'React without any functions' ),
      CE( 'p', null, [
      CE('b', null, 'Nice'),
      ' if we can shorten the code a bit.',
    ] ),
  ]),
  document.getElementById('root')
);

幸运的是聪明人已经有了这个想法,所以你可以使用 JSX 来代替,例如:

ReactDOM.render(
  <div>
    <h1>React without any functions</h1>
      <p>
      <b>Even nicer: </b>
      we can just use JSX!
    </p>
  </div>,
  document.getElementById('root')
);

这只是一种不同的语法,它会在构建时转换为 javascript。

【讨论】:

  • “React 不会做任何静态分析来确定一个函数是否是一个组件” 这并不完全正确。组件必须以大写字母开头(即函数名),因为它将以小写字母开头的组件视为 DOM 标签 (reference)
  • 好点。很高兴在这里提一下。但是that uppercase requirement is JSX 在构建时解释。对于 React,它可以在 .createElement( myFunction ) 中使用小写函数(除非您安装了一些额外的代码分析工具)。
  • 我不知道,因为我不使用createElement。但很高兴知道。
  • "这实际上或多或少是关于这个主题的完整故事" - 您忘记的重要部分是功能 components 呈现为一个元素,不仅仅是作为一个函数调用,确实有一个生命周期。 React 确实保留了一些全局状态,允许您在渲染函数组件时使用诸如 useStateuseRefuseEffect 之类的钩子。
  • 你是对的。我只是想不出一种方法来整合它并保持答案“简短”。我仍然认为这不是深入解释这一点的地方,但也许我应该在某处整合一个提示......看看我是否有一个想法如何做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 2019-09-21
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 2015-03-15
  • 1970-01-01
相关资源
最近更新 更多