这篇文章主要讲解了“从零开始学习React”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“从零开始学习React”吧!0: 从一次最简单的 React 渲染说起上面这三行代码是一个再简单不过的 React 应用:在 root 根结点上渲染一个 Hello World! h2 节点。第一步的目标是用原生 DOM 方式替换 React 代码。JSX熟悉 React 的读者都知道,我们直接在组件渲染的时候返回一段类似 html 模版的结构,这个就是所谓的 JSX。JSX 本质上还是 JS,是语法糖而不是 html 模版(相比 html 模版要学习千奇百怪的语法比如:{{#if value}},JSX 可以直接使用 JS 原生的 && || map reduce 等语法更易学表达能力也更强)。一般需要 babel 配合@babel/plugin-transform-react-jsx 插件(babel 转换过程不是本文重点,感兴趣可以阅读插件源码)转换成调用 React.createElement,函数入参如下:例如上面的例子中的 React.createElement 返回一个包含元素(element)信息的对象,即:react 官方实现还包括了很多额外属性,简单起见本文未涉及,参看官方定义。这个对象描述了 React 创建一个节点(node)所需要的信息,type 就是 DOM 节点的名字,比如这里是 h2,也可以是函数组件,后面会讲到。props 包含所有元素免费云主机、域名的属性(比如 title)和特殊属性 children,children 可以包含其他元素,从根到叶也就能构成一颗完整的树,也就是描述了整个 UI 界面。为了避免含义不清,“元素”特指 “React elements”,“节点”特指 “DOM elements”。ReactDOM.render下面替换掉 ReactDOM.render 调用,这里 React 会把元素更新到 DOM。对比元素对象,首先用 element.type 创建节点,再把非 children 属性(这里是 title)赋值给节点。然后创建 children 节点,由于 children 是字符串,故创建 textNode 节点,并把字符串赋值给 nodeValue,这里之所以用 createTextNode 而不是 innerText,是为了方便之后统一处理。再把 children 节点 text 插到元素节点的子节点上,最后把元素节点插到根结点即完成了这次 React 的替换。像上面代码 element 这样 JSX 转成的描述 UI 界面的对象就是所谓的 虚拟 DOM,相对的 node 即 真实 DOM。render/渲染 过程就是把虚拟 DOM 转换成真实 DOM 的过程。I: 实现 createElement 函数第一步首先实现 createElement 函数,把 JSX 转换成 JS。以下面这个新的渲染为例,createElement 就是把 JSX 结构转成元素描述对象。就像之前示例那样,createElement 返回一个包含 type 和 props 的元素对象,描述节点信息。children 可能包含字符串或者数字这类基础类型值,给这里值包裹成 TEXT_ELEMENT 特殊类型,方便后面统一处理。注意:React 并不会包裹字符串这类值,如果没有 children 也不会创建空数组,这里简单起见,统一这样处理可以简化我们的代码。我们把本文的框架叫做 redact,以区别 react。示例 app 如下。但是我们还是习惯用 JSX 来写组件,这里还能用吗?答案是能的,只需要加一行注释即可。注意第一行注释 @jsx 告诉 babel 用 Redact.createElement 替换默认的 React.createElement。或者直接修改 .babelrc 配置文件的 pragma 项,就不用每次都添加注释了。II: 实现 render 函数实现我们的 render 函数,目前只需要添加节点到 DOM,删除和更新操作后面再加。上面的代码放在了 CodeSandbox(在线开发环境),项目基于 Create React App 模版,试一试改下面的代码验证下。redact-1III: 并发模式 / Concurrent Mode在我们深入其他 React 功能之前,先对代码重构,引入 React 最新的并发模式(截止本文发表该功能还未正式发布)。可能读者会疑惑我们目前连最基本的组件状态更新都还没实现就先实现并发模式,其实目前代码逻辑还十分简单,现在重构,比之后实现所有功能再回头要容易很多,所谓积重难返就是这个道理。有经验的开发者很容易发现上面的 render 代码有一个问题,渲染子节点时递归遍历了整棵树,当我们页面非常复杂时很容易阻塞主线程(和 stack over flow, 堆栈溢出),我们都知道每个页面是单线程的(不考虑 worker 线程),主线程阻塞会导致页面不能及时响应高优先级操作,如用户点击或者渲染动画,页面给用户 “很卡,难用” 的负面印象,这肯定不是我们想要的。因此,理想情况下,我们应该把 render 拆成更细分的单元,每完成一个单元的工作,允许浏览器打断渲染响应更高优先级的的工作,这个过程即 “并发模式”。这里我们用 requestIdleCallback 这个浏览器 API 来实现。这个 API 有点类似 setTimeout,不过不是我们告诉浏览器什么时候执行回调函数,而是浏览器在线程空闲(idle)的时侯主动执行回调函数。React 目前已经不用这个 API 了,而是用 调度器/scheduler 这个包,自己实现调度算法。但它们核心思路是类似的,简化起见用 requestIdleCallback 足矣。IV: Fibers 数据结构为了方便描述渲染树和单元任务,React 设计了一种数据结构 “fiber 树”。每个元素都是一个 fiber,每个 fiber 就是一个单元任务。假如我们渲染如下这样一棵树:用 Fiber 树来描述就是:在 render 函数我们创建根 fiber,再把它设为 nextUnitOfWork。在 workLoop 函数把 nextUnitOfWork 给 performUnitOfWork 执行,主要包含以下三步:鸿蒙官方战略合作共建——HarmonyOS技术社区把元素添加到 DOM为元素的后代创建 fiber 节点选择下一个单元任务,并返回为了完成这些目标需要设计的数据结构方便找到下一个任务单元。所以每个 fiber 直接链接它的第一个子节点(child),子节点链接它的兄弟节点(sibling),兄弟节点链接到父节点(parent)。 示意图如下(注意不同节点之间的高亮箭头):当我们完成了一个 fiber 的单元任务,如果他有一个 子节点/child 则这个节点作为 nextUnitOfWork。如下图所示,当完成 div 单元任务之后,下一个单元任务就是 h2。如果一个 fiber 没有 child,我们用 兄弟节点/sibling 作为下一个任务单元。如下图所示,p 节点没有 child 而有 sibling,所以下一个任务单元是 a 节点。如果一个 fiber 既没有 child 也没有 sibling,则找到父节点的兄弟节点,。如下图所示的 a 和 h3。如果父节点没有兄弟节点,则继续往上找,直到找到一个兄弟节点或者到达 fiber 根结点。到达根结点即意味本次 render 任务全部完成。把这个思路用代码表达如下:V: render 和 commit 阶段我们的代码还有一个问题。每完成一个任务单元都把节点添加到 DOM 上。请记住,浏览器是可以打断渲染流程的,如果还没渲染完整棵树就把节点添加到 DOM,用户会看到残缺不全的 UI 界面,给人一种很不专业的印象,这肯定不是我们想要的。因此需要重构节点添加到 DOM 这部分代码,整棵树(fiber)渲染完成之后再一次性添加到 DOM,即 React commit 阶段。具体来说,去掉 performUnitOfWork 的 fiber.parent.dom.appendChild 代码,换成如下代码。VI: 更新和删除节点/Reconciliation目前我们只添加节点到 DOM,还没考虑更新和删除节点的情况。要处理这2种情况,需要对比上次渲染的 fiber 和当前渲染的 fiber 的差异,根据差异决定是更新还是删除节点。React 把这个过程叫 Reconciliation。因此我们需要保存上一次渲染之后的 fiber 树,我们把这棵树叫 currentRoot。同时,给每个 fiber 节点添加 alternate 属性,指向上一次渲染的 fiber。代码较多,建议按 render ⟶ workLoop ⟶ performUnitOfWork ⟶ reconcileChildren ⟶ workLoop ⟶ commitRoot ⟶ commitWork ⟶ updateDom 顺序阅读。
本篇内容主要讲解“css3怎么设置动画”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“css3怎么设置动画”吧! 首先我们来了解一下css3实现简单动画需要用到的属性:animation属性,@keyframes…