React组件返回时实际发生了什么?

Qwe*_*rty 6 javascript components render reactjs

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

在渲染之前 渲染后

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
  }
}
Run Code Online (Sandbox Code Playgroud)

我之前的问题是" 如何读取渲染组件的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 
Run Code Online (Sandbox Code Playgroud)

Tha*_*ara 4

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

<div>
  <MyComponent/>
</div>
Run Code Online (Sandbox Code Playgroud)

例如,上面的 JSX 代码片段将在编译过程中转换为以下 JavaScript 代码。

React.createElement(
  "div",
  null,
  React.createElement(MyComponent, null)
);
Run Code Online (Sandbox Code Playgroud)

您可以使用Babel 在线 repl 工具尝试一下。因此,如果我们使用普通 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
  }
}
Run Code Online (Sandbox Code Playgroud)

通过查看上面的代码,我们可以理解,并<BComponent crmStatus={...}/>没有创建BComponent类的新对象或调用类render的方法BComponent。它只是创建一个带有BComponenttype 和crmStatusprop 的 ReactElement。那么什么是 ReactElement?ReactElement 是一个令人痛苦的 JavaScript 对象,具有一些属性。我建议您阅读React 官方博客中的这篇文章,以深入了解 React 组件、元素和实例。

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

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

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

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

希望这可以帮助!