当 React 组件 returns 时究竟发生了什么?
What actually happens when React component returns?
我注意到组件 return 之前和 return 之后的数据存在差异。
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
在回答问题之前,有必要了解一下什么是 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
的新对象class或者调用BComponent
的render
方法=].它只是创建一个具有 BComponent
类型和 crmStatus
属性的 ReactElement。那么什么是 ReactElement? ReactElement 是一个具有某些属性的痛苦 JavaScript 对象。我建议您阅读 this post from official React blog 以深入了解 React 组件、元素和实例。
An element is a plain object describing a component instance or DOM node and its desired properties. It contains only information about
the component type (for example, a Button), its properties (for
example, its color), and any child elements inside it.
基本上,您在控制台中打印的是两个不同类型的 React 元素。左边描述 DOM 类型 'article'
的节点,右边描述 BComponent
类型的 React 组件实例。所以你不能指望它们是一样的。
那么React在什么地方创建BComponent
的实例呢?实际上,这发生在 React 代码内部。通常,我们无法通过应用程序代码中的渲染方法访问这些实例或 return。
但是,React 仍然提供了一个名为 'refs' 的逃生通道,您可以通过它显式访问子组件的实例。您也许可以使用该方法来解决您原来的问题。
希望对您有所帮助!
我注意到组件 return 之前和 return 之后的数据存在差异。
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
在回答问题之前,有必要了解一下什么是 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
的新对象class或者调用BComponent
的render
方法=].它只是创建一个具有 BComponent
类型和 crmStatus
属性的 ReactElement。那么什么是 ReactElement? ReactElement 是一个具有某些属性的痛苦 JavaScript 对象。我建议您阅读 this post from official React blog 以深入了解 React 组件、元素和实例。
An element is a plain object describing a component instance or DOM node and its desired properties. It contains only information about the component type (for example, a Button), its properties (for example, its color), and any child elements inside it.
基本上,您在控制台中打印的是两个不同类型的 React 元素。左边描述 DOM 类型 'article'
的节点,右边描述 BComponent
类型的 React 组件实例。所以你不能指望它们是一样的。
那么React在什么地方创建BComponent
的实例呢?实际上,这发生在 React 代码内部。通常,我们无法通过应用程序代码中的渲染方法访问这些实例或 return。
但是,React 仍然提供了一个名为 'refs' 的逃生通道,您可以通过它显式访问子组件的实例。您也许可以使用该方法来解决您原来的问题。
希望对您有所帮助!