reactjs 在渲染过程中,为什么要将函数组件 Package 在React.createElement中,而不是通过函数调用使用其返回的元素?

but5z9lq  于 2023-05-22  发布在  React
关注(0)|答案(2)|浏览(126)
const App = () => {
 return React.createElement(
   "div",
   {},
   React.createElement('h1', {}, "Adopt The Pet"))
 }
}

ReactDOM.render(App(), document.getElementById("root")); // this works

// vs

ReactDOM.render(React.createElement(App), document.getElementById("root"));

我正在阅读一篇介绍react的教程,作者使用了第二个版本和一个新的React.createElement() Package 。即使在浏览了相关的react文档之后,我也不知道这样做的必要性。
第一个版本已经返回了一个React.createElement(),那么为什么不 * 使用那个返回的元素 *,而不是把它 Package 在一个新的React.createElement()中呢?

**编辑:**即使是React文档,如果你将文档的JSX转换为React.createElement()调用,也会使用课程作者的方法,但同样,他们没有解释为什么。

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

// React.createElement(Welcome, {name : Sara})
const element = <Welcome name="Sara" />; 

// Why not just do this?
const element =  Welcome({Sara})

ReactDOM.render(
  element,
  document.getElementById('root')
);
rseugnpd

rseugnpd1#

这与“React组件”实际上是什么有关。根据React文档:
从概念上讲,组件就像JavaScript函数。它们接受任意输入(称为“props”),并返回描述屏幕上应该显示什么的React元素。- https://reactjs.org/docs/components-and-props.html
归结起来,我将React组件理解为“返回React元素的函数”(现在完全忽略类)。

function component() {
  return React.createElement('h1', null, 'Hello World')
}

因此,如果是这种情况,我们应该能够将React组件直接传递给ReactDOM.render()React.createElement()

ReactDOM.render(component, document.getElementById("root"))
// or
React.createElement('div', null, component)

但我们不能这不管用它给我们以下错误:
警告:函数不能作为React子函数。如果返回的是Component而不是render,则可能会发生这种情况。或者你想调用这个函数而不是返回它。
当然,我们可以通过调用我们的函数来解决这个问题:

ReactDOM.render(component(), document.getElementById("root"))
// or
React.createElement('div', null, component())

但这真的是一个React组件吗?不,它只是调用一个普通的旧函数,最终获得一个React元素作为返回值。为了进一步说明这一点,看看当我们尝试使用useState钩子时会发生什么:

function component() {
  const [state, setState] = React.useState(0);
  return React.createElement('h1', null, 'Hello World')
}

ReactDOM.render(component(), document.getElementById("root"))

未捕获错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。
但是等一下,我们以为我们有一个函数React组件?
返回React元素的函数在作为第一个参数传递给React.createElement()之前不会成为“React组件”。
这是有道理的,如果我们思考它。如果你定义了一个函数,React就无法知道你的函数是一个React组件。你将函数作为引用传递,但React不知道你传递的东西最终会返回一个React元素(根据我们的定义)。我们需要以某种方式向React表明我们的函数确实是一个“React组件”。我们的函数作为React.createElement()的第一个参数

// Regular old function
function component() {
  return React.createElement('h1', null, 'Hello World')
}

// becomes a React component
React.createElement(component)

除了上面的useState()钩子之外,React还需要控制作为参数传递给我们函数的props,因此当props更改时,它可以重新呈现。我们必须给予React控制我们的功能。所以,为了修改我们之前对React元素的定义,我们在这里着陆:
React组件是“返回React元素的函数,并作为第一个参数传递给React.createElement()”
当我们使用JSX时,这些都被抽象掉了,所以我认为这就是为什么人们不真正谈论它。

oo7oh9g9

oo7oh9g92#

除了下面@Galupuf的answer和直接调用函数组件时不能使用钩子的限制之外,React's "Design Principles"还提供了一个清晰的解释,说明为什么不鼓励手动调用函数组件。

**即使你的组件被描述为函数,当你使用React时,你也不会直接调用它们。**每个组件都会返回一个描述,说明需要渲染什么,这个描述可能包括用户编写的组件和平台特定的组件。由React在未来某个时候“展开”,并根据组件的渲染结果递归地将更改实际应用于UI树。

这是一个微妙的区别,但却是一个有力的区别。因为你不调用那个组件函数,而是让React调用它,这意味着React有能力在必要时延迟调用它。

相关问题