VDOM和DOM-diff
类型验证(prop-types)
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为以下 JS 原生类型
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、子元素或数组)。
optionalNode: PropTypes.node,
// 一个 React 元素
optionalElement: PropTypes.element,
// 你也可以声明属性为某个类的实例,这里使用 JS 的
// instanceof 操作符实现。
optionalMessage: PropTypes.instanceOf(Message),
// 你也可以限制你的属性值是某个特定值之一
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 限制它为列举类型之一的对象
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 一个指定元素类型的数组
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 一个指定类型的对象
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 一个指定属性及其类型的对象
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// 你也可以在任何 PropTypes 属性后面加上 `isRequired`
// 后缀,这样如果这个属性父组件没有提供时,会打印警告信息
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你也可以指定一个自定义验证器。它应该在验证失败时返回
// 一个 Error 对象而不是 `console.warn` 或抛出异常。
// 不过在 `oneOfType` 中它不起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 不过你可以提供一个自定义的 `arrayOf` 或 `objectOf`
// 验证器,它应该在验证失败时返回一个 Error 对象。 它被用
// 于验证数组或对象的每个值。验证器前两个参数的第一个是数组
// 或对象本身,第二个是它们对应的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};React V16.7.0-alpha Hooks
Rules of Hooks
只能在顶层调用Hooks 。不要在循环,条件或嵌套函数中调用Hook
只能在functional component中使用
虚拟 DOM 和 DOM Diff
虚拟DOM
用 JS 去按照 DOM 结构来实现的树形结构对象,你也可以叫做 DOM 对象
实现一下虚拟DOM
参数分析:
type: 指定元素的标签类型,如'li', 'div', 'a'等
props: 表示指定元素身上的属性,如class, style, 自定义属性等
children: 表示指定元素是否有子节点,参数以数组的形式传入
渲染虚拟DOM
DOM-diff闪亮登场
说到DOM-diff那一定要清楚其存在的意义,给定任意两棵树,采用先序深度优先遍历的算法找到最少的转换步骤 作用: 根据两个虚拟对象创建出补丁,描述改变的内容,将这个补丁用来更新DOM
比较规则
新的DOM节点不存在{type: 'REMOVE', index}
文本的变化{type: 'TEXT', text: 1}
当节点类型相同时,去看一下属性是否相同,产生一个属性的补丁包{type: 'ATTR', attr: {class: 'list-group'}}
节点类型不相同,直接采用替换模式{type: 'REPLACE', newNode}
patch补丁更新
patch做了什么?
用一个变量来得到传递过来的所有补丁allPatches
patch方法接收两个参数(node, patches)
在方法内部调用walk方法,给某个元素打上补丁
walk方法里获取所有的子节点
给子节点也进行先序深度优先遍历,递归walk
如果当前的补丁是存在的,那么就对其打补丁(doPatch)
doPatch打补丁方法会根据传递的patches进行遍历
判断补丁的类型来进行不同的操作:
属性ATTR for in去遍历attrs对象,当前的key值如果存在,就直接设置属性setAttr; 如果不存在对应的key值那就直接删除这个key键的属性
文字TEXT 直接将补丁的text赋值给node节点的textContent即可
替换REPLACE 新节点替换老节点,需要先判断新节点是不是Element的实例,是的话调用render方法渲染新节点;不是的话就表明新节点是个文本节点,直接创建一个文本节点就OK了。之后再通过调用父级parentNode的replaceChild方法替换为新的节点
删除REMOVE 直接调用父级的removeChild方法删除该节点
package
mirrorx
参考文献
Last updated
Was this helpful?