博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React 深度学习:ReactElementValidator
阅读量:5122 次
发布时间:2019-06-13

本文共 6719 字,大约阅读时间需要 22 分钟。

path:packages/react/src/ReactElementValidator.js

ReactElementValidator.js 模块中的方法对 ReactElement 中的 createElementcreateFactorycloneElement 方法进行了包装。 这些方法会在创建 React 元素时进行一些额外的检查, 并在检查不通过时打印一些警告信息。

这些方法被用在开发环境中。

这些检查包括:

  • key 检查
  • props 与元素类型是否匹配

对于这部分的学习,我们应该从另一方面认识一下这些警告信息。 这些警告是 React 传达给我们的很有用的信息,说明我们在使用 React 的过程中忽略了一些细节。 因此,我们需要尽可能修复这些警告。

createElementWithValidation

export function createElementWithValidation(type, props, children) {  const validType = isValidElementType(type);    // 我们在这种情况下发出警告,但不会抛出。  // 我们期望元素创建成功,在渲染中可能会出现错误。  if (!validType) {    // 在开发模式下打印警告  }  const element = createElement.apply(this, arguments);  // 如果使用模拟或自定义函数,结果可能为空。  // TODO: 当这些不再被允许作为 type 参数时,删除它。  if (element == null) {    return element;  }  // 如果 type 无效,那么跳过键警告  // 因为key 验证逻辑不期望非字符串/函数类型,并且可能抛出让人困惑的错误  // 我们不希望异常行为在 dev 和 prod 之间有所不同。  // (渲染将抛出一条有用的消息,一旦 type 被修复,就会出现键警告。)  if (validType) {    for (let i = 2; i < arguments.length; i++) {      validateChildKeys(arguments[i], type);    }  }  if (type === REACT_FRAGMENT_TYPE) {    validateFragmentProps(element);  } else {    validatePropTypes(element);  }  return element;}复制代码

用于判断目标是否是有效的 React 元素类型

createFactoryWithValidation

export function createFactoryWithValidation(type) {  const validatedFactory = createElementWithValidation.bind(null, type);  validatedFactory.type = type;  // Legacy hook: remove it  if (__DEV__) {    // do something  }  return validatedFactory;}复制代码

cloneElementWithValidation

export function cloneElementWithValidation(element, props, children) {  const newElement = cloneElement.apply(this, arguments);  for (let i = 2; i < arguments.length; i++) {    validateChildKeys(arguments[i], newElement.type);  }  validatePropTypes(newElement);  return newElement;}复制代码

其他方法

validateExplicitKey

/** * Warn if the element doesn't have an explicit key assigned to it. * This element is in an array. The array could grow and shrink or be * reordered. All children that haven't already been validated are required to * have a "key" property assigned to it. Error statuses are cached so a warning * will only be shown once. * * @internal * @param {ReactElement} element Element that requires a key. * @param {*} parentType element's parent's type. */function validateExplicitKey(element, parentType) {  if (!element._store || element._store.validated || element.key != null) {    return;  }  element._store.validated = true;  const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);  if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {    return;  }  ownerHasKeyUseWarning[currentComponentErrorInfo] = true;  // Usually the current owner is the offender, but if it accepts children as a  // property, it may be the creator of the child that's responsible for  // assigning it a key.  let childOwner = '';  if (    element &&    element._owner &&    element._owner !== ReactCurrentOwner.current  ) {    // Give the component that originally created this child.    childOwner = ` It was passed a child from ${getComponentName(      element._owner.type,    )}.`;  }  setCurrentlyValidatingElement(element);  if (__DEV__) {    // do something  }  setCurrentlyValidatingElement(null);}复制代码

validateChildKeys

/** *  * 确保 * 1. 数组中的每个元素在静态位置定义了显式 key 属性 * 2. 或在可迭代对象中具有有效 key 属性 * * @internal * @param {ReactNode} node Statically passed child of any type. * @param {*} parentType node's parent's type. */function validateChildKeys(node, parentType) {  if (typeof node !== 'object') {    return;  }  // 遍历数组  if (Array.isArray(node)) {    for (let i = 0; i < node.length; i++) {      const child = node[i];      if (isValidElement(child)) {        validateExplicitKey(child, parentType);      }    }  } else if (isValidElement(node)) {    // This element was passed in a valid location.    if (node._store) {      node._store.validated = true;    }  } else if (node) {    // 遍历可迭代对象    const iteratorFn = getIteratorFn(node);    if (typeof iteratorFn === 'function') {      // Entry iterators used to provide implicit keys,      // but now we print a separate warning for them later.      if (iteratorFn !== node.entries) {        const iterator = iteratorFn.call(node);        let step;        while (!(step = iterator.next()).done) {          if (isValidElement(step.value)) {            validateExplicitKey(step.value, parentType);          }        }      }    }  }}复制代码

validateFragmentProps

/** *  * 给定一个 fragment,验证它只能使用 fragment props * @param {ReactElement} fragment */function validateFragmentProps(fragment) {  setCurrentlyValidatingElement(fragment);  const keys = Object.keys(fragment.props);  for (let i = 0; i < keys.length; i++) {    const key = keys[i];    if (key !== 'children' && key !== 'key') {      warning(        false,        'Invalid prop `%s` supplied to `React.Fragment`. ' +          'React.Fragment can only have `key` and `children` props.',        key,      );      break;    }  }  if (fragment.ref !== null) {    warning(false, 'Invalid attribute `ref` supplied to `React.Fragment`.');  }  setCurrentlyValidatingElement(null);}复制代码

fragment 只能接收 children 属性和 key 属性,提供其他属性的时候会得到警告。

为 fragment 提供 ref 属性的时候会得到一个单独的警告。

validatePropTypes

/** * * 给定一个元素,验证它的 props 是否遵循 type 提供的 propTypes 定义。 * * @param {ReactElement} element */function validatePropTypes(element) {  const type = element.type;  if (type === null || type === undefined || typeof type === 'string') {    return;  }  const name = getComponentName(type);  let propTypes;  if (typeof type === 'function') {    propTypes = type.propTypes;  } else if (    typeof type === 'object' &&    (type.$$typeof === REACT_FORWARD_REF_TYPE ||      // 注意:这里,Memo 只检查外部 props。      // 内部 props 在 reconciler 中检查      type.$$typeof === REACT_MEMO_TYPE)  ) {    propTypes = type.propTypes;  } else {    return;  }  if (propTypes) {    setCurrentlyValidatingElement(element);    checkPropTypes(      propTypes,      element.props,      'prop',      name,      ReactDebugCurrentFrame.getStackAddendum,    );    setCurrentlyValidatingElement(null);  } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) { // 写错属性名 propTypes -> PropTypes    propTypesMisspellWarningShown = true;    warningWithoutStack(      false,      'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',      name || 'Unknown',    );  }  // 使用过时的 getDefaultProps 会得到警告,需要使用 defaultProps 替代  if (typeof type.getDefaultProps === 'function') {    warningWithoutStack(      type.getDefaultProps.isReactClassApproved,      'getDefaultProps is only used on classic React.createClass ' +        'definitions. Use a static property named `defaultProps` instead.',    );  }}复制代码

转载于:https://juejin.im/post/5d10e9c651882531e71c304a

你可能感兴趣的文章
Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
查看>>
第23月第24天 git命令 .git-credentials git rm --cached git stash clear
查看>>
java SE :标准输入/输出
查看>>
一些方便系统诊断的bash函数
查看>>
jquery中ajax返回值无法传递到上层函数
查看>>
css3之transform-origin
查看>>
Master选举原理
查看>>
[ JAVA编程 ] double类型计算精度丢失问题及解决方法
查看>>
小别离
查看>>
好玩的-记最近玩的几个经典ipad ios游戏
查看>>
PyQt5--EventSender
查看>>
Sql Server 中由数字转换为指定长度的字符串
查看>>
Java 多态 虚方法
查看>>
万能的SQLHelper帮助类
查看>>
tmux的简单快捷键
查看>>
[Swift]LeetCode922.按奇偶排序数组 II | Sort Array By Parity II
查看>>
《绿色·精简·性感·迷你版》易语言,小到不可想象
查看>>
Android打包key密码丢失找回
查看>>
VC6.0调试技巧(一)(转)
查看>>
类库与框架,强类型与弱类型的闲聊
查看>>