本文共 4326 字,大约阅读时间需要 14 分钟。
查看专栏其它文章:
本人是个新手,写下博客用于自我复习、自我总结。 如有错误之处,请各位大佬指出。 学习资料来源于:尚硅谷
之前的文章里已经使用过 JavaScript 的 map() 方法来创建列表。在这里再详细说明其它内容。
简单使用演示:
const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((numbers) =>
然后我们再将以上实例重构成一个组件,组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items
,意思就是需要包含 key。
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) =>
通常情况下,请不要忘记加 key。那这个 Key 到底是用来做什么的,且选取什么值都可以吗?
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。且一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key ( id :自己建立的,用于区分每个数据)。
const todoItems = todos.map((todo) =>
当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:
const todoItems = todos.map((todo, index) => // 只有在没有确定的 id 时使用
复杂一些的情况:元素的 key 只有在它和它的兄弟节点对比时才有意义。
比方说,如果你提取出一个 ListItem 组件,你应该把 key 保存在数组中的这个 <ListItem />
元素上,而不是放在 ListItem 组件中的 <li>
元素上。
function ListItem(props) { // 这里不需要指定key: return
在这里需要注意:key 只会作为给 React 的提示,不会传递给你的组件。比如在这里子组件中,就不能读出 props.key。如果您的组件中需要使用和 key 相同的值,请将其作为属性传递。
说回正题,数组元素中使用的 key 在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的键。
function Blog(props) { const sidebar = (
{
post.content}从React开篇就说到了虚拟DOM,也提到了对于React高效的原因:
虚拟(virtual)DOM, 不总是直接操作DOM
DOM Diff算法, 最小化页面重绘
接下来将对虚拟DOM的相关内容进行一些简单的说明。
在说到何为 虚拟DOM 前,需要先说明何为 真实DOM 和其解析的流程。这部分详细内容可以看:视频中的内容讲的很详细。
对于浏览器渲染引擎的大致工作流程如下(简化):
第一步,用HTML分析器,分析HTML元素,构建一颗DOM树。
第二步,用CSS分析器,分析CSS文件和元素上的样式,生成页面的样式表。
第三步,将DOM树和样式表,关联起来,构建一颗Render树。
第四步,有了Render树,浏览器开始布局,为每个Render树上的节点确定一个在显示屏上出现的精确坐标。
第五步,Render树和节点显示坐标都有了,就调用每个节点paint方法,把它们绘制出来。
然后再经过一个复杂的渲染过程,就将内容渲染了出来。
在这个过程中,当我们改变一个元素的尺寸位置属性时,会重新进行样式计算、布局、绘制以及后面的所有流程,这种行为被称为重排。
当我们改变某个元素的颜色属性时,不会重新触发布局,但还是会触发样式计算和绘制,这种行为被称为重绘。
操作真实DOM的代价?
而在这个过程中,JS操作真实DOM的代价还是很大的。当我们用传统的开发模式,原生JS操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。在一次操作中,我需要更新10个DOM节点,浏览器收到第一个DOM请求后并不知道还有9次更新操作,因此会马上执行流程,最终执行10次。例如,第一次计算完,紧接着下一个DOM更新请求,这个节点的坐标值就变了,前一次计算为无用功。计算DOM节点坐标值就是白白的浪费性能。
那虚拟DOM有什么好处?
虚拟DOM就是为了解决浏览器性能问题而被设计出来的。若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的内容保存到本地一个JS对象中,最终将这个JS对象一次性挂到DOM树上,再进行后续操作,避免大量无谓的计算量。(也就是现在我们看到的 React 和 Vue 都是这样操作)
diff算法是虚拟DOM技术的必然产物
这个diff算法是虚拟DOM技术的必然产物,因为我们需要对新旧虚拟DOM作对比,然后将变化的地方更新在真实DOM上。如果对diff算法感兴趣,可以查阅相关资料。
就比如上面列表中 key 的作用就是为了高效的更新虚拟DOM,其原理就是通过key精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个更新渲染过程更加高效,减少DOM操作量,提高性能。
在上面已经说到了,虚拟DOM 通过 Diff算法,实现了最小化页面重绘,即:可以更少的操作真实DOM,减少操作DOM的次数,更新页面的次数也就减少了。接下来我们将验证这点,虚拟DOM是否真的可以最小化页面重绘。
vDOM
因为时间在不断变化(通过 setState 更新状态),所以会重新创建虚拟DOM树。而在这个过程中,虚拟DOM会对 新 / 旧 内容进行比较,然后对有差异的部分去进行局部重绘。假如是整体重绘,那么在输入框中输入一些内容应该也会导致差异。而无论我们怎么向输入框中输入内容,也不会引起虚拟DOM对其的更新。而向输入框中输入信息却无法导致更新,是因为之前在表单时提到过,表单元素本身虽然能够保留一些内部状态,并根据用户输入进行更新,但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。
原理图:
React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。
相关用法就不在这里赘述了,如果对AJAX不熟悉,可以查阅相关文章:
常用的ajax请求库
jQuery: 比较重, 如果需要另外引入不建议使用
axios: 轻量级, 建议使用
a. 封装XmlHttpRequest对象的ajax b. promise风格 c. 可以用在浏览器端和node服务器端fetch: 原生函数, 但老版本浏览器不支持
a. 不再使用XmlHttpRequest对象提交ajax请求 b. 为了兼容低版本的浏览器, 可以引入兼容库fetch.js使用简例(axios):
ajax
使用简例(jQuery):
ajax
转载地址:http://hmyki.baihongyu.com/