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

时间:2016-05-20 12:04:07

标签: javascript reactjs components render

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

before render after render

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
  }
}

我以前的问题将是&#34; How to read rendered component's className?&#34;,但我将问题分解为回答实际发生的事情以及为什么它真的如此开始惹我生气,甚至可能会给我提示解决我的问题。

所以问题是:

组件实际发生了什么,为什么会这样?我的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 

1 个答案:

答案 0 :(得分:4)

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

<div>
  <MyComponent/>
</div>

举个例子,上面的JSX代码片段将在编译过程中转换为以下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
  }
}

通过查看上面的代码,我们可以理解<BComponent crmStatus={...}/>没有创建BComponent类的新对象或调用render BComponent方法。它只是创建一个带有BComponent类型和crmStatus道具的ReactElement。什么是ReactElement? ReactElement是一个具有一些属性的痛苦JavaScript对象。我建议您阅读this post from official React blog以深入了解React组件,元素和实例。

  

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

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

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

但是,React仍提供名为'refs'的转义填充,您可以显式访问子组件的实例。您可以使用该方法来解决原始问题。

希望这有帮助!