React是如何在后台运行的

React is a very popular JavaScript library. With over 5.5 million weekly downloads, React is enjoying great popularity. But not a lot of React developers know how React works under the hood.

React是一个非常流行JavaScript库。 每周的下载量超过550万,React非常受欢迎。 但是并不是很多React开发人员都知道React是如何工作的。

In this post, I'll try to uncover some interesting things about React which you, as a React developer, might find fascinating. Let's start at the beginning.

在这篇文章中,我将尝试揭示一些关于React的有趣的事情,作为React开发人员,您可能会着迷。 让我们从头开始。

But before we start, if you're a React developer, I have some exciting news for you! Once you complete this article, you'll get to develop something cool with React and win prizes on the way :)

但是在我们开始之前,如果您是React开发人员,那么我有一些令人振奋的消息! 完成本文后,您将可以使用React开发一些很酷的东西,并在此过程中赢取奖品:)

React是做什么的? (What does React do?)

At its very core, React basically maintains a tree for you. This tree is able to do efficient diff computations on the nodes.

从根本上讲,React基本上为您维护了一棵树。 该树能够在节点上进行高效的差异计算。

Think of your HTML code as a tree. In fact, that is exactly how the browser treats your DOM (your rendered HTML on the browser). React allows you to effectively re-construct your DOM in JavaScript and push only those changes to the DOM which have actually occurred.

将您HTML代码视为一棵树。 实际上,这正是浏览器对待DOM(您在浏览器上呈现HTML)的方式。 React允许您在JavaScript中有效地重构DOM,并将实际发生的更改仅推送到DOM。

JSX是语法糖 (JSX is syntactic sugar)

There's nothing like JSX - neither to JavaScript, nor to the browser. JSX is simply syntactic sugar for creating very specific JavaScript objects.

没有像JSX一样的东西-JavaScript和浏览器都没有。 JSX只是用于创建非常特定JavaScript对象的语法糖。

When you write something like:

当您编写类似的内容时:

const tag = <h1>Hello</h1>

what you're essentially doing is this:

您实际上在做什么是这样的:

const tag = React.createElement("h1", {}, "Hello")

You see, when you start writing nested stuff, not only is this difficult to code, but it also becomes very inconvenient to maintain such a codebase. JSX thus helps you bring the cleanliness of HTML to the power of JavaScript.

您会发现,当您开始编写嵌套的东西时,不仅很难编写代码,而且维护这样的代码库也变得非常不便。 JSX因此可以帮助您将HTML的纯净性带入JavaScript的力量。

But what does React.createElement do itself? It creates a plain old JavaScript object. In fact, you can manually call it and see for yourself!

但是React.createElement本身会做什么? 它创建一个普通的旧JavaScript对象。 实际上,您可以手动调用它并亲自查看!

You see, we've an object like this:

你看,我们有一个像这样的对象:

{
    $$typeof: Symbol(react.element),
    key: null,
    props: {children: "Hello"},
    ref: null,
    type: "div"
}

And if we start nesting elements like this:

如果我们开始嵌套这样的元素:

React.createElement('div', { }, 
React.createElement('p', {}, 'A p inside a div')
)

We would start getting nested objects:

我们将开始获取嵌套对象:

So now you know, once all the JSX is parsed and all the React.createElement calls have been resolved, we land with one giant nested object like above.

所以现在您知道,一旦所有的JSX都被解析并且所有的React.createElement调用都已解析,我们就可以像上面那样放置一个巨型嵌套对象。

React渲染器 (React Renderer)

Now, if you go back to the point where we start our app, you'll see that in your index.js file, you would find the following line:

现在,如果您回到启动应用程序的位置,您会在index.js文件中看到以下内容:

// .. prev code

ReactDOM.render(<App />, container)

From above, we know that when <App /> has been done parsing, this is just a huge object of React elements. Then how is React able to construct actual divs and p tags out of it? Meet ReactDOM.

从上面我们知道, <App />解析完成后,这只是React元素的巨大对象。 那么React如何从中构造出实际的div和p标签呢? 认识ReactDOM。

ReactDOM in turn, recursively creates nodes depending on their 'type' property and appends them finally to the DOM.

反过来,ReactDOM根据其“类型”属性递归创建节点,并将其最终附加到DOM。

It should be clear at this point that why decoupling React from the renderers is actually a great move! What React does is, simply construct a tree of UI which could be used not only on web, but on environments like mobile too, given that a renderer is available which is able to communicate with the host OS. Here, React Native comes to play. You see, React Native uses React library, but not ReactDOM as the render. Instead, the package react-native itself is a renderer.

在这一点上应该很清楚,为什么将React与渲染器解耦实际上是一个很大的举措! React的作用是,只需构建一个UI树,不仅可以在Web上使用,而且还可以在移动设备等环境中使用,前提是可以使用能够与主机OS进行通信的渲染器。 在这里,React Native开始发挥作用。 您会看到,React Native使用React库,而不使用ReactDOM作为渲染器。 相反,包react-native本身就是一个渲染器。

We do this in a react native application to start the app:

我们在react本机应用程序中执行以下操作以启动该应用程序:

const { AppRegistry } = require('react-native')
AppRegistry.registerComponent('app', () => MainComponent)

Look! No ReactDOM. Why not? Because we don't have methods like appendChild, neither do we have a DOM like environment. Instead, for mobiles, we need support for UI directly from OS. But the React library doesn't need to know that, the renderer (React Native) takes care of that.

看! 没有ReactDOM。 为什么不? 因为我们没有诸如appendChild之类的方法,所以我们也没有类似DOM的环境。 相反,对于手机,我们需要直接从OS支持UI。 但是React库不需要知道这一点,渲染器(React Native)可以解决这个问题。

React对帐 (React Reconciliation)

When we say that React maintains a copy of DOM using virtual DOM in JavaScript, and it uses to diff it to any changes and apply it to real DOM, we don't want React to brute-force its way. React, in fact does very lazy reconciliation. React would make the least amount of changes possible, i.e. it would try to re-use elements, attributes, and even styles if possible!

当我们说React使用JavaScript中的虚拟DOM维护DOM的副本,并用来将其与任何更改进行比较并将其应用于真实DOM时,我们不希望React蛮力地实现。 React,实际上做得很懒惰。 React将尽可能少地进行更改,即,如果可能,它将尝试重用元素,属性甚至样式!

Consider this example:

考虑以下示例:

<img className="class-1" alt="stuff" />

Let's say you change this JSX expression to the below one using some condition or some state:

假设您使用某种条件或某种状态将此JSX表达式更改为以下表达式:

<img className="class-1" alt="something else" />

Now while diffing, React would see that well, the img tag makes use of the same className both in old and new trees, so why modify it. And it would just modify your alt attribute and move on.

现在,在进行比较时,React会很好地看到,img标签在新旧树中都使用了相同的className,所以为什么要对其进行修改。 它只会修改您的alt属性并继续前进。

However, there's a catch. Because we don't want React to do a lot of computation on diffing part, React would assume that if a parent has changed, its containing subtree has definitely changed. For example:

但是,有一个陷阱。 因为我们不希望React在差异部分进行大量计算,所以React会假设如果父对象已更改,则其包含的子树肯定已更改。 例如:

<div className="class-1">
	<p>I did not change</p>
</div>

If you change this JSX to the below using condition/state:

如果使用条件/状态将此JSX更改为以下内容:

<p className="class-1">
	<p>I did not change</p>
</p>

Although you could see that we don't need to re-create the inner p tag, but React has no way of knowing that while traversing the tree from top (unless, of course you perform heavy tree diffing, which are much expensive algorithms than the heuristic O(n) react follows for diffing). So, React decides to destroy all children (i.e. calling their cleanup functions in useEffect, or componentWillUnmount in class based components) and re-create the children from scratch.

尽管您可以看到我们不需要重新创建内部p标签,但是React从顶部遍历树时并没有办法知道(除非您执行繁重的树差异处理,这比然后进行启发式O(n)React进行扩散)。 因此,React决定销毁所有子项(即在useEffect中调用其清理函数,或在基于类的组件中调用componentWillUnmount)并从头开始重新创建子项。

React键 (React Keys)

When adding/removing elements in a node, React would simply loop over the children in old tree and children in the new tree of the node and mark the places where it needs to perform any addition/removal. But this has a disadvantage without additional help from developer. Consider this example:

在节点中添加/删除元素时,React会简单地循环遍历该节点的老树中的孩子和新树中的孩子,并标记需要执行任何添加/删除的位置。 但这有一个缺点,即没有开发人员的额外帮助。 考虑以下示例:

<ul>
    <li>A</li>
    <li>B</li>
</ul>

Consider this is changed to the below by condition/state:

请考虑根据条件/状态将其更改为以下内容:

<ul>
    <li>Z</li>
    <li>A</li>
    <li>B</li>
<ul>

Now, when React would start comparing the two lists for difference, it would find the difference at child node 1, would mutate the old A to new Z, then again at child node 2, would mutate it from the old B to new A, and then finally append the new B node.

现在,当React将开始比较两个列表的差异时,它将发现在子节点1上的差异,将旧的A突变为新的Z,然后在子节点2上再次将其从旧的B突变为新的A,然后最后追加新的B节点。

However, a better way would've been to preserve the existing A and B nodes and just prepend the Z node. But how would React know about that? React keys would help.

但是,更好的方法是保留现有的A和B节点,而仅在Z节点之前。 但是React怎么知道呢? React键会有所帮助。

Keys just provide a nice way to React to know which elements have changed or not changed while diffing. Now, instead of comparing the whole element, React would compare the keys of the children to see which element needs to be added/removed. The below way is an efficient way of performing the same thing:

键只是提供了一种很好的方式来让React知道差异时哪些元素已更改或未更改。 现在,React不再比较整个元素,而是比较子元素的键,以查看需要添加/删除的元素。 以下方法是执行相同操作的有效方法:

<ul>
    <li key="A">A</li>
    <li key="B">B</li>
</ul>

Now, if this gets changed to:

现在,如果将其更改为:

<ul>
    <li key="Z">Z</li>
    <li key="A">A</li>
    <li key="B">B</li>
</ul>

React would now know that keys 'A' and 'B' already exists, so we just need to add the new element with key 'Z'.

现在,React将知道键“ A”和“ B”已经存在,因此我们只需要添加具有键“ Z”的新元素。

Are you a React developer? Show off your React skills by developing a 3 minute interactive game in React and win hoodies, shirts and coffee mugs! Take part in codecomp by joining codedamn's discord server here

您是React开发人员吗? 通过在React中开发一个3分钟的互动游戏来展示您的React技能 ,并赢得连帽衫,衬衫和咖啡杯 通过在此处加入Codedamn的Discord服务器参与codecomp

So these were some important concepts I believe would be really helpful for you as a React developers to start understanding the core of React and how it actually works. Feel free to pass down any suggestions or questions you have about the same.

因此,这些是一些重要的概念,我认为作为React开发人员,这些知识对您真正了解React的核心及其实际工作方式将非常有帮助。 随意传递任何关于您的建议或问题。

You can follow me on twitter for more JS/coding tweets and things. Peace!

您可以在Twitter上关注我,以了解更多JS /编码推文和其他内容。 和平!

翻译自: https://www.freecodecamp.org/news/react-under-the-hood/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值