当 React 组件返回时实际发生了啥?

Posted

技术标签:

【中文标题】当 React 组件返回时实际发生了啥?【英文标题】:What actually happens when React component returns?当 React 组件返回时实际发生了什么? 【发布时间】:2016-09-17 16:41:27 【问题描述】:

我注意到返回之前和返回组件后的数据之间存在差异。

class AComponent extends Component 
  render() 
    const body = <BComponent crmStatus=.../>
    debugger // log body on the right
    // ... render as static html to electron window
    return false
  


class BComponent extends Component 
  render() 
    const resultRender = <article className='large'>...</article>
    debugger // log resultRender on the left
    return resultRender
  

我以前的问题是“How to read rendered component's className?”,但我已经将问题拆分为回答 实际发生的事情以及为什么会这样真的开始困扰我,甚至可能给出我提示解决我的问题。

所以问题是:

组件实际发生了什么,为什么会这样?我的 render() 函数中可以有非常复杂的逻辑,但我想使用这些组件并不容易。

const headerContact = isContactInCRM ? <p>..</p> : <div>..</div>
const headerCallBtnsOrInfo = isSipEnabled && <div>..buttons..</div>
const callTimer = callDuration && <span>callDuration</span>
const footerNotes = <footer>..</footer>
const someImportedComponent = <MyComponent />

const resultRender = <section>
  headerContact
  headerCallBtnsOrInfo
  callTimer
  footerNotes
  someImportedComponent
</section>

// there is a difference in data between headerContact and someImportedComponent
// when traversing the resultRender's tree in console 

【问题讨论】:

我不确定这个问题是否仍然相关,但我在提供的数据中发现了一个主要问题: - 右侧屏幕截图是 BComponent 组件存根的转储 - 左侧屏幕截图是 article 的转储组件存根...这就是它们具有不同类型的原因(注意类与字符串article)您可能想在第二种情况下转储“this”... 组件返回后会形成一个VDOM(react会添加ids等)并追加到html中。但是,目前还不清楚您要解决什么问题! @ZbigniewZagórski 感谢您的洞察力。这个问题已经很老了,在打开赏金之前我什至没有再读过它。你写的正是我当时的想法,但没看懂。可惜我不能奖励评论者。 【参考方案1】:

在回答这个问题之前,有必要先看看 JSX 是什么。它只是为React.createElement(component, props, ...children) 函数提供语法糖。

<div>
  <MyComponent/>
</div>

例如,上面的JSX sn-p在编译过程中会转化为下面的javascript代码。

React.createElement(
  "div",
  null,
  React.createElement(MyComponent, null)
);

您可以使用Babel online repl tool 进行尝试。因此,如果我们使用普通 JavaScript 重写您的示例代码(在编译 JSX 之后),它将是这样的。

class AComponent extends Component 
  render() 
    const body = React.createElement(BComponent,  crmStatus: '...' );
    debugger // log body on the right
    // ... render as static html to electron window
    return false
  


class BComponent extends Component 
  render() 
    const resultRender = React.createElement('article', className: 'large' , '...' );
    debugger // log resultRender on the left
    return resultRender
  

通过查看上面的代码,我们可以了解到&lt;BComponent crmStatus=.../&gt; 并没有创建BComponent 类的新对象,也没有调用BComponentrender 方法。它只是创建一个带有 BComponent 类型和 crmStatus 属性的 ReactElement。那么什么是 ReactElement? ReactElement 是一个带有一些属性的痛苦 JavaScript 对象。我建议您阅读this post from official React blog 以深入了解 React 组件、元素和实例。

元素是描述组件实例或 DOM 节点及其所需属性的普通对象。 它仅包含有关 组件类型(例如,一个按钮),它的属性(对于 例如,它的颜色),以及其中的任何子元素。

基本上,您在控制台中打印的是两个不同类型的 React 元素。左边是描述 'article' 类型的 DOM 节点,右边是描述 BComponent 类型的 React 组件实例。所以你不能指望它们是一样的。

那么 React 在哪里创建BComponent 的实例呢?实际上,这发生在 React 代码内部。通常,我们无法访问这些实例或应用程序代码中它们的渲染方法返回的内容。

然而,React 仍然提供了一个名为 'refs' 的逃生舱口,您可以显式访问子组件的实例。您也许可以使用该方法来解决您最初的问题。

希望这会有所帮助!

【讨论】:

以上是关于当 React 组件返回时实际发生了啥?的主要内容,如果未能解决你的问题,请参考以下文章

React的class组件及属性详解!

React 功能组件 - 当组件返回元素数组时,如何将 refs 传递回父级?

React:组件的生命周期

React:组件的生命周期

React:组件的生命周期

当 React 组件中的音频元素 src 属性发生更改并且在 linux 上重新加载窗口时,Electron 变为空白