Props 和 PropTypes 是在 React 组件之间传递只读属性的重要机制。
我们可以使用 React props(属性的缩写)将数据从一个组件发送到另一个组件。如果一个组件接收到错误类型的 props,它可能会导致您的应用程序出现错误和意外错误。
由于 JavaScript 没有内置的类型检查解决方案,因此许多开发人员使用TypeScript 和 Flow等扩展。然而,React 有一个用于 props 验证的内部机制,称为PropTypes。在本文中,我们将学习如何使用 React PropTypes 验证 props。
-
React 道具是如何工作的?
-
为什么要在 React 中验证 props?
-
在 React 中使用 PropType
-
prop-types在 React 中使用库
-
React PropTypes 验证器
-
用于类型检查 React 道具的自定义验证器
-
PercentageStat在 React 中验证
如果您更喜欢视觉学习者,我建议您查看以下有关 React PropTypes 的视频教程:
React 道具是如何工作的?
使用 React props,您可以在调用该组件时向该组件发送数据,包括数字、字符串、函数、对象和数组。如果您有多个组件,则可以将数据从一个组件传递到另一个组件。
要在组件之间传递 props,您可以在调用组件时添加它们,就像在调用常规 JavaScript 函数时传递参数一样。
为什么要在 React 中验证 props?
在开发 React 应用程序时,您需要构建和定义您的 props 以避免错误和错误。就像一个函数可能有强制参数一样,React 组件可能需要定义一个 prop,否则,它将无法正确呈现。忘记将所需的道具传递给需要它的组件可能会导致您的应用程序出现意外行为。
考虑下面的代码:
import React from 'react'; import ReactDOM from 'react-dom'; function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } function App() { return ( <div> <h1>Male Population</h1> <div> <PercentageStat label="Class 1" total={360} score={203} /> <PercentageStat label="Class 2" total={206} /> <PercentageStat label="Class 3" score={107} /> <PercentageStat label="Class 4" /> </div> </div> ) } const rootElement = document.getElementById('root'); ReactDOM.render(<App />, rootElement);
在上面的代码中,PercentageStat组件需要三个 props 才能正确渲染,label,score和total. score为和道具设置默认值total,以防它们未提供。PercentageStat在组件中被渲染四次App,每次使用不同的道具。
下图显示了带有一些额外Bootstrap样式的应用程序的外观:
根据使用情况,该label道具预计为string. 同样,score并且total必须是numeric值,因为它们用于计算percent。此外,total预计永远不会0因为它被用作除数。
下面的代码显示了一个修改后的应用程序,它PercentageStat使用无效的 props 渲染组件:
function App() { return ( <div> <h1>Male Population</h1> <div> <PercentageStat label="Class 1" total="0" score={203} /> <PercentageStat label="Class 2" total={0} /> <PercentageStat label="Class 3" score={f => f} /> <PercentageStat label="Class 4" total={{}} score="0" /> </div> </div> ) }
现在,应用程序视图如下图所示:
在 React 中使用 PropType
PropTypes 是React为组件 props添加类型检查的内部机制。React 组件使用一个特殊的属性调用propTypes来设置类型检查:
/** * FUNCTIONAL COMPONENTS */ function ReactComponent(props) { // ...implement render logic here } ReactComponent.propTypes = { // ...prop type definitions here } /** * CLASS COMPONENTS: METHOD 1 */ class ReactComponent extends React.Component { // ...component class body here } ReactComponent.propTypes = { // ...prop type definitions here } /** * CLASS COMPONENTS: METHOD 2 * Using the `static` class properties syntax */ class ReactComponent extends React.Component { // ...component class body here static propTypes = { // ...prop type definitions here } }
当 props 被传递给 React 组件时,它们会根据propTypes属性中配置的类型定义进行检查。当为 prop 传递无效值时,JavaScript 控制台上会显示警告:
如果为 React 组件设置了默认 propspropTypes ,则在对. 因此,默认值也受道具类型定义的约束。
请记住,类型检查propTypes只能在开发模式下进行,使您能够在将 React 应用程序发布到生产环境之前捕获它中的错误。
prop-types在 React 中使用库
在 React v15.5.0 之前,PropTypesReact 包中提供了一个名为的实用程序,它提供了许多验证器来配置组件道具的类型定义。您可以使用React.PropTypes.
但是,在更高版本的 React 中,此实用程序已移至名为prop-types. 要访问该PropTypes实用程序,您需要添加prop-types作为项目的依赖项:
npm install prop-types --save
您可以将其导入到您的项目文件中,如下所示:
import PropTypes from 'prop-types';
要了解有关如何使用prop-types以及它与使用React.PropTypes和所有可用验证器有何不同的更多信息,请查看官方prop-types 文档。
React PropTypes 验证器
该PropTypes实用程序导出了大量用于配置类型定义的验证器。下面,我们将列出基本、可渲染、实例、多个、集合和所需属性类型的可用验证器。
基本类型
以下是基本数据类型的验证器:
-
PropTypes.any: prop 可以是任何数据类型
-
PropTypes.bool: 道具应该是一个布尔值
-
PropTypes.number: 道具应该是一个数字
-
PropTypes.string: 道具应该是一个字符串
-
PropTypes.func: prop 应该是一个函数
-
PropTypes.array: prop 应该是一个数组
-
PropTypes.object:道具应该是一个对象
-
PropTypes.symbol: 道具应该是一个符号
Component.propTypes = { anyProp: PropTypes.any, booleanProp: PropTypes.bool, numberProp: PropTypes.number, stringProp: PropTypes.string, functionProp: PropTypes.func, arrayProp: PropTypes.array, objectPerop: PropTypes.object, symbolProp: PropTypes.symbol, }
可渲染类型
PropTypes 还导出以下验证器,以确保 React 可以呈现 传递给 prop 的值。
-
PropTypes.node: prop 应该是 React 可以渲染的任何东西,比如包含这些类型的数字、字符串、元素、数组或片段
-
PropTypes.element: prop 应该是一个 React 元素
Component.propTypes = { nodeProp: PropTypes.node, elementProp: PropTypes.element }
验证器的一个常见用途PropTypes.element是确保组件有一个子组件。如果组件没有子组件或多个子组件,JavaScript 控制台上会显示警告:
Component.propTypes = { children: PropTypes.element.isRequired }
实例类型
如果你需要一个 prop 是一个特定 JavaScript 类的实例,你可以使用PropTypes.instanceOf验证器,它利用了底层的 JavaScriptinstanceof操作符:
Component.propTypes = { personProp: PropTypes.instanceOf(Person) }
多种类型
PropTypes 还导出验证器,这些验证器可以允许有限的一组值或多组数据类型用于道具。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →
-
PropTypes.oneOf: prop 仅限于一组指定的值,将其视为枚举
-
PropTypes.oneOfType: prop 应该是一组指定的类型之一,表现得像类型的联合
Component.propTypes = { enumProp: PropTypes.oneOf([true, false, 0, 'Unknown']), unionProp: PropTypes.oneOfType([ PropType.bool, PropType.number, PropType.string, PropType.instanceOf(Person) ]) }
集合类型
除了PropTypes.array和PropTypes.object验证器,PropTypes还提供了验证器,用于对数组和对象进行更精细的验证。
PropTypes.arrayOf
PropTypes.arrayOf确保 prop 是一个数组,其中所有项目都与指定类型匹配:
Component.propTypes = { peopleArrayProp: PropTypes.arrayOf( PropTypes.instanceOf(Person) ), multipleArrayProp: PropTypes.arrayOf( PropTypes.oneOfType([ PropType.number, PropType.string ]) ) }
PropTypes.objectOf
PropTypes.objectOf确保 prop 是一个对象,其中所有属性值都与指定类型匹配:
Component.propTypes = { booleanObjectProp: PropTypes.objectOf( PropTypes.bool ), multipleObjectProp: PropTypes.objectOf( PropTypes.oneOfType([ PropType.func, PropType.number, PropType.string, PropType.instanceOf(Person) ]) ) }
PropTypes.shape
当需要对对象道具进行更详细的验证时,您可以使用PropTypes.shape. 它确保 prop 是一个对象,其中包含一组具有指定类型值的指定键:
Component.propTypes = { profileProp: PropTypes.shape({ id: PropTypes.number, fullname: PropTypes.string, gender: PropTypes.oneOf(['M', 'F']), birthdate: PropTypes.instanceOf(Date), isAuthor: PropTypes.bool }) }
PropTypes.exact
对于严格或精确的对象匹配,PropTypes.exact如果组件中存在额外的属性,则会发出警告:
Component.propTypes = { subjectScoreProp: PropTypes.exact({ subject: PropTypes.oneOf(['Maths', 'Arts', 'Science']), score: PropTypes.number }) }
所需类型
到目前为止,PropTypes我们探索的所有验证器都允许 prop 是可选的。但是,您可以链接isRequired到任何 prop 验证器,以确保在未提供 prop 时显示警告:
Component.propTypes = { requiredAnyProp: PropTypes.any.isRequired, requiredFunctionProp: PropTypes.func.isRequired, requiredSingleElementProp: PropTypes.element.isRequired, requiredPersonProp: PropTypes.instanceOf(Person).isRequired, requiredEnumProp: PropTypes.oneOf(['Read', 'Write']).isRequired, requiredShapeObjectProp: PropTypes.shape({ title: PropTypes.string.isRequired, date: PropTypes.instanceOf(Date).isRequired, isRecent: PropTypes.bool }).isRequired }
用于类型检查 React 道具的自定义验证器
通常,您需要为组件 props 定义一些自定义验证逻辑,例如,以确保向 props 传递有效的电子邮件地址。笔趣阁会员版App,完美爆破无需注册登录,看遍全网几乎99%小说和漫画!prop-types允许您定义可用于类型检查道具的自定义验证函数。
基本的自定义验证器
自定义验证函数接受三个参数:
-
props: 包含传递给组件的所有道具的对象
-
propName: 要验证的道具的名称
-
componentName: 组件的名称
如果验证失败,它应该返回一个Error对象。不应抛出该错误。此外,您不应console.warn在自定义验证函数中使用:
const isEmail = function(props, propName, componentName) { const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/; if (!regex.test(props[propName])) { return new Error(`Invalid prop `${propName}` passed to `${componentName}`. Expected a valid email address.`); } } Component.propTypes = { email: isEmail, fullname: PropTypes.string, date: PropTypes.instanceOf(Date) }
您还可以将自定义验证函数与PropTypes.oneOfType. 下面的示例使用isEmail前面代码片段中的自定义验证函数:
Component.propTypes = { email: PropTypes.oneOfType([ isEmail, PropTypes.shape({ address: isEmail }) ]) }
该组件在以下两种情况下都有效:
<Component email="glad@me.com" /> <Component email={{ address: 'glad@me.com' }} />
自定义验证器和集合
您还可以通过PropTypes.arrayOf和使用自定义验证函数PropTypes.objectOf。以这种方式使用时,将为数组或对象中的每个键调用自定义验证函数。
自定义验证函数采用五个参数而不是三个参数:
-
propValue: 数组或对象本身
-
key: 迭代中当前item的key
-
componentName: 组件的名称
-
location: 验证数据的位置,通常prop
-
propFullName:正在验证的当前项目的完全解析名称。对于数组,这将是array[index]; 对于一个对象,它将是object.key
下面是isEmail用于集合类型的自定义验证函数的修改版本:
const isEmail = function(propValue, key, componentName, location, propFullName) { const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/; if (!regex.test(propValue[key])) { return new Error(`Invalid prop `${propFullName}` passed to `${componentName}`. Expected a valid email address.`); } } Component.propTypes = { emails: PropTypes.arrayOf(isEmail) }
通用的自定义验证器
考虑到我们对自定义验证函数的了解,让我们继续创建通用的自定义验证器,我们可以将其用作独立验证器以及集合类型。
我们可以使isEmail自定义验证函数成为一个通用的验证器,只需稍作修改。我们将添加一个返回或的prop变量。有了这个,我们的自定义验证器既可以单独使用,也可以与集合一起使用:propFullName``key
const isEmail = function(propValue, key, componentName, location, propFullName) { // Get the resolved prop name based on the validator usage const prop = (location && propFullName) ? propFullName : key; const regex = /^((([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,})))?$/; if (!regex.test(propValue[key])) { return new Error(`Invalid prop `${prop}` passed to `${componentName}`. Expected a valid email address.`); } } Component.propTypes = { email: PropTypes.oneOfType([ isEmail, PropTypes.shape({ address: isEmail }) ]), emails: PropTypes.arrayOf(isEmail) }
PercentageStat在 React 中验证
以下代码片段将 prop 类型添加到PercentageStat我们在本教程开始时查看的组件中:
import React from 'react'; import PropTypes from 'prop-types'; // The PercentageStat component function PercentageStat({ label, score = 0, total = Math.max(1, score) }) { return ( <div> <h6>{ label }</h6> <span>{ Math.round(score / total * 100) }%</span> </div> ) } // Checks if a value is numeric // Either a finite number or a numeric string function isNumeric(value) { const regex = /^(\+|-)?((\d*\.?\d+)|(\d+\.?\d*))$/; return Number.isFinite(value) || ((typeof value === "string") && regex.test(value)); } // Checks if value is non-zero // Value is first converted to a number function isNonZero(value) { return +value !== 0; } // Takes test functions as arguments and returns a custom validation function. // Each function passed in as argument is expected to take a value argument // expected to accept a value and return a Boolean if it passes the validation. // All tests must pass for the custom validator to be marked as passed. function validatedType(...validators) { return function(props, propName, componentName) { const value = props[propName]; const valid = validators.every(validator => { if (typeof validator === "function") { const result = validator(value); return (typeof result === "boolean") && result; } return false; }); if (!valid) { return new Error(`Invalid prop \`${propName}\` passed to \`${componentName}\`. Validation failed.`); } } } // Set the propTypes for the component PercentageStat.propTypes = { label: PropTypes.string.isRequired, score: validatedType(isNumeric), total: validatedType(isNumeric, isNonZero) }
结论
在本教程中,我们学习了如何改进我们的 React 组件并确保它们使用 prop 类型按预期工作。通过在我们的开发环境中使用道具类型验证我们的道具,我们可以防止错误和错误在部署后影响我们的应用程序。