React 备忘清单

适合初学者的综合 React 备忘清单。

入门

介绍

React 是一个用于构建用户界面的 JavaScript 库。

  1. import {createRoot} from 'react-dom/client'
  2. import App from './App'

  1. const elm = document.getElementById('app')
  2. const root = createRoot(elm);
  3. root.render(<App />);

快速创建 React 项目 (CRA)

  1. npx create-react-app my-app

导入多个导出

  1. import React, {Component} from 'react'
  2. import ReactDOM from 'react-dom'

  1. export class Hello extends Component {
  2. ...
  3. }
  4. export default function World() {
  5. /* ... */
  6. }

使用 export 导出 Helloexport default 导出 World 组件

  1. import World, { Hello } from './hello.js';

使用 import 导入 Hello 组件,在示例中使用。

React 组件中的 CSS

```jsx {2,5} import React from “react”; import “./Student.css”;

export const Student = (

);

  1. 注意:类属性 `className`
  2. ```jsx
  3. const divStyle = {
  4. backgroundImage: 'url(' + imgUrl + ')',
  5. };
  6. export const Student = (
  7. <div style={divStyle}></div>
  8. );

属性

  1. <Student name="Julie" age={23}
  2. pro={true} />

函数组件 Student 中访问属性

  1. function Student(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }

Class 组件 Student 中访问属性

  1. class Student extends React.Component {
  2. render() {
  3. return (
  4. <h1>Hello, {this.props.name}</h1>
  5. );
  6. }
  7. }

class 组件使用 this.props 访问传递给组件的属性。

Children

  1. function Example() {
  2. return (
  3. <AlertBox>
  4. <h1>您有待处理的通知</h1>
  5. </AlertBox>
  6. )
  7. }

函数 AlertBox 组件

```jsx {4} function AlertBox(props) { return (

{props.children}
); }

  1. ----
  2. ```jsx
  3. {props.children}

Class AlertBox 组件,与函数组件 AlertBox 组件相同

```jsx {5} class AlertBox extends React.Component { render () { return (

{this.props.children}
); } }

  1. ----
  2. ```jsx
  3. {this.props.children}

children 作为子组件的的属性传递。

State

函数中的 State,Hook 是 React 16.8 的新增特性

```jsx {4,8} import { useState } from ‘react’;

function Student() { const [count, setCount] = useState(0); const click = () => setCount(count + 1); return (

您点击了 {count} 次

); }

  1. 使用 `setState` 更新状态,下面是函数组件读取状态
  2. ```jsx
  3. <p>您点击了 {count} 次</p>

Class 中的 State

```jsx {6,12,20} import React from ‘react’;

class Student extends React.Component { constructor(props) { super(props); this.state = {count: 1}; // 确保函数可以访问组件属性(ES2015) this.click = this.click.bind(this); } click() { const count = this.state.count; this.setState({ count: count + 1}) } render() { return (

您点击了{this.state.count}次

); } }

  1. 使用 `setState` 更新状态,`class` 组件中不能使用 <yel>~~hooks~~</yel>。下面是 `class` 组件读取状态
  2. ```jsx
  3. <p>您点击了{this.state.count}次</p>

循环

  1. const elm = ['one', 'two', 'three'];
  2. function Student() {
  3. return (
  4. <ul>
  5. {elm.map((value, index) => (
  6. <li key={index}>{value}</li>
  7. ))}
  8. </ul>
  9. );
  10. }

key 值在兄弟节点之间必须唯一

事件监听

  1. export default function Hello() {
  2. function handleClick(event) {
  3. event.preventDefault();
  4. alert("Hello World");
  5. }
  6. return (
  7. <a href="/" onClick={handleClick}>
  8. Say Hi
  9. </a>
  10. );
  11. }

函数注入

  1. function addNumbers(x1, x2) {
  2. return x1 + x2;
  3. }
  4. const element = (
  5. <div>
  6. {addNumbers(2, 5)}
  7. </div>
  8. );

嵌套

  1. import { useState } from 'react'
  2. import Avatar from './Avatar';
  3. import Profile from './Profile';
  4. function Student() {
  5. const [count, setCount] = useState(0);
  6. return (
  7. <div>
  8. <Avatar src={count} />
  9. <Profile username={count} />
  10. </div>
  11. );
  12. }

Portals

React 并没有创建一个新的 div。它只是把子元素渲染到 domNode 中。domNode 是一个可以在任何位置的有效 DOM 节点。

  1. render() {
  2. return ReactDOM.createPortal(
  3. this.props.children,
  4. domNode
  5. );
  6. }

提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案

Fragment

```jsx {1,6,9} import { Fragment } from ‘react’ import Avatar from ‘./Avatar’; import Profile from ‘./Profile’;

const Student = () => ( );

  1. `v16.2.0` 开始 `Fragment` 可用于返回多个子节点,而无需向 DOM 添加额外的包装节点。或者使用 `<></>` 效果是一样的。
  2. ```jsx {2,5}
  3. const Student = () => (
  4. <>
  5. <Avatar src="./demo.jpg" />
  6. <Profile username="name" />
  7. </>
  8. );

查看: Fragments & strings

返回字符串

```jsx {2} render() { return ‘Look ma, no spans!’; }

  1. 您可以只返回一个字符串。查看: [Fragments & strings](https://reactjs.org/blog/2017/09/26/react-v16.0.html#new-render-return-types-fragments-and-strings)
  2. ### 返回数组
  3. ```jsx
  4. const Student = () => [
  5. <li key="A">First item</li>,
  6. <li key="B">Second item</li>
  7. ];

不要忘记 key!查看: Fragments & strings

Refs 转发

  1. const FancyButton = React.forwardRef(
  2. (props, ref) => (
  3. <button ref={ref} className="btn">
  4. {props.children}
  5. </button>
  6. )
  7. );

使用

  1. // 你可以直接获取 DOM button 的 ref:
  2. const ref = React.createRef();
  3. <FancyButton ref={ref}>
  4. 点击我
  5. </FancyButton>;

Class 组件内部使用 ref 属性

```jsx {6,10} import {Component,createRef} from ‘react’

class MyComponent extends Component { constructor(props) { super(props); this.myRef = createRef(); }

render() { return

; } }

  1. 提示:Refs 适用于类组件,但不适用于函数组件(除非您使用 useRef hook,请参阅[hooks](#hooks))
  2. ### 函数组件内部使用 ref 属性
  3. ```jsx {3,9}
  4. function CustomTextInput(props) {
  5. // 这里必须声明 $input,这样 ref 才可以引用它
  6. const $input = useRef(null);
  7. function handleClick() {
  8. $input.current.focus();
  9. }
  10. return (
  11. <div>
  12. <input type="text" ref={$input} />
  13. <input
  14. type="button" value="聚焦文本输入"
  15. onClick={handleClick}
  16. />
  17. </div>
  18. );
  19. }

严格模式 StrictMode

```jsx {3,8}

  1. ----
  2. - [识别不安全的生命周期](https://zh-hans.reactjs.org/docs/strict-mode.html#identifying-unsafe-lifecycles)
  3. - [关于使用过时字符串 ref API 的警告](https://zh-hans.reactjs.org/docs/strict-mode.html#warning-about-legacy-string-ref-api-usage)
  4. - [关于使用废弃的 findDOMNode 方法的警告](https://zh-hans.reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage)
  5. - [检测意外的副作用](https://zh-hans.reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects)
  6. - [检测过时的 context API](https://zh-hans.reactjs.org/docs/strict-mode.html#detecting-legacy-context-api)
  7. - [确保可复用的状态](https://zh-hans.reactjs.org/docs/strict-mode.html#ensuring-reusable-state)
  8. 突出显示应用程序中潜在问题的工具。请参阅:[严格模式](https://zh-hans.reactjs.org/docs/strict-mode.html)
  9. ### Profiler
  10. <!--rehype:wrap-class=col-span-2-->
  11. 测量一个 React 应用多久渲染一次以及渲染一次的 `代价`
  12. ```jsx
  13. <Profiler id="Navigation" onRender={callback}>
  14. <Navigation {...props} />
  15. </Profiler>

为了分析 Navigation 组件和它的子代。应该在需要时才去使用它。

:- :-
id(string) 发生提交的 Profiler 树的 id
onRender(function) 组件树任何组件 “提交” 一个更新的时候调用这个函数

onRender 回调函数

:- :-
`phase: “mount” \ “update”` 判断是由 props/state/hooks 改变 或 “第一次装载” 引起的重渲染
actualDuration: number 本次更新在渲染 Profiler 和它的子代上花费的时间
baseDuration: number 在 Profiler 树中最近一次每一个组件 render 的持续时间
startTime: number 本次更新中 React 开始渲染的时间戳
commitTime: number 本次更新中 React commit 阶段结束的时间戳
interactions: Set 当更新被制定时,“interactions” 的集合会被追踪

默认值

Class 组件默认 props

  1. class CustomButton extends React.Component {
  2. // ...
  3. }
  4. CustomButton.defaultProps = {
  5. color: 'blue'
  6. };

使用

  1. <CustomButton /> ;

不传值 props.color 将自动设置为 blue

Class 组件默认 state

  1. class Hello extends Component {
  2. constructor (props) {
  3. super(props)
  4. this.state = { visible: true }
  5. }
  6. }

在构造 constructor()中设置默认状态。

  1. class Hello extends Component {
  2. state = { visible: true }
  3. }

函数组件默认 props

  1. function CustomButton(props) {
  2. const { color = 'blue' } = props;
  3. return <div>{color}</div>
  4. }

函数组件默认 state

  1. function CustomButton() {
  2. const [color, setColor]=useState('blue')
  3. return <div>{color}</div>
  4. }

JSX

介绍

JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖

  1. <MyButton color="blue" shadowSize={2}>
  2. 点击我
  3. </MyButton>

会编译为

  1. React.createElement(
  2. MyButton,
  3. {color: 'blue', shadowSize: 2},
  4. '点击我'
  5. );

没有子节点

  1. <div className="sidebar" />

会编译为

  1. React.createElement(
  2. 'div',
  3. {className: 'sidebar'}
  4. )

JSX 点语法

  1. const Menu = ({ children }) => (
  2. <div className="menu">{children}<div>
  3. );
  4. Menu.Item = ({ children }) => (
  5. <div>{children}<div>
  6. );
  7. <Menu>
  8. <Menu.Item>菜单一</Menu.Item>
  9. <Menu.Item>菜单二</Menu.Item>
  10. <Menu>

JSX Element

  1. let element = <h1>Hello, world!</h1>;
  2. let emptyHeading = <h1 />;
  3. const root = ReactDOM.createRoot(
  4. document.getElementById('root')
  5. );
  6. const element = <h1>Hello, world</h1>;
  7. root.render(element);

参考:渲染元素

JSX 属性

  1. const avatarUrl = "img/picture.jpg"
  2. const element = <img src={avatarUrl} />;
  3. const element = (
  4. <button className="btn">
  5. 点击我
  6. </button>
  7. );

注意:类属性 className

JSX 表达式

  1. let name = '张三';
  2. let element = <h1>Hello, {name}</h1>;
  3. function fullName(firstName, lastName) {
  4. return firstName + ' ' + lastName;
  5. }
  6. let element = (
  7. <h1>
  8. Hello, {fullName('三', '张')}
  9. </h1>
  10. );

JSX style

  1. const divStyle = {
  2. color: 'blue',
  3. backgroundImage: 'url(' + imgUrl + ')',
  4. };
  5. function MyComponent() {
  6. return <div style={divStyle}>组件</div>;
  7. }

JSX dangerouslySetInnerHTML

  1. const markup = {__html: '我 &middot; 你' };
  2. const MyComponent = () => (
  3. <div dangerouslySetInnerHTML={markup} />
  4. );

dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。

JSX htmlFor

  1. const MyComponent = () => (
  2. <div>
  3. <input type="radio" id="ab" name="v">
  4. <label for="ab">HTML</label>
  5. </div>
  6. );

forJS 中是保留字,JSX 元素使用了 htmlFor 代替

JSX defaultValue

非受控组件的属性,设置组件第一次挂载时的 value

  1. <textarea defaultValue="Hello" />

<input><select><textarea> 支持 value 属性

JSX defaultChecked

非受控组件的属性,设置组件是否被选中

  1. <input type="radio" defaultChecked />

类型为 checkboxradio 时,组件支持 checked 属性

JSX className

属性用于指定 CSSclass

  1. <div className="warp">...</div>

React 中使用 Web Components 使用 class 属性代替

JSX 条件渲染

  1. import React from "react";
  2. function formatName(user) {
  3. return user.firstName
  4. + ' '
  5. + user.lastName;
  6. }
  7. export function Greeting(user) {
  8. if (user) {
  9. return (
  10. <h1>你好, {formatName(user)}!</h1>
  11. );
  12. }
  13. return (
  14. <h1>你好, 先生。</h1>
  15. );
  16. }

注意:组件必须总是返回一些东西。

使用

  1. <Greeting firstName="三" lastName="张" />

JSX 三目运算符 / 与运算符 &&

  1. export default function Weather(props) {
  2. const isLoggedIn = props.isLoggedIn;
  3. return (
  4. <div>
  5. <b>{isLoggedIn ? '已' : '未'}</b>登录。
  6. </div>
  7. );
  8. }

  1. {isShow && <div>内容</div>}

JSX 组件

  1. <Dropdown>
  2. 下拉列表
  3. <Menu>
  4. <Menu.Item>菜单一</Menu.Item>
  5. <Menu.Item>菜单二</Menu.Item>
  6. <Menu.Item>菜单三</Menu.Item>
  7. </Menu>
  8. </Dropdown>

组件名称以大驼峰式命名。

JSX 元素变量

  1. function Greeting(props) {
  2. let button;
  3. if (props.isLoggedIn) {
  4. button = <UserGreeting />;
  5. } else {
  6. button = <GuestGreeting />;
  7. }
  8. return <div>{button}</div>;
  9. }

JSX 注释

  1. function Student() {
  2. const [count, setCount] = useState(0);
  3. return (
  4. <Fragment>
  5. {/* 这里写注释 */}
  6. </Fragment>
  7. );
  8. }

组件

函数组件

  1. import React from 'react';
  2. const UserName = () => <h1>Kenny</h1>;
  3. export default function UserProfile() {
  4. return (
  5. <div className="UserProfile">
  6. <div>Hello</div>
  7. <UserName />
  8. </div>
  9. );
  10. }

注意:每个组件都需要一个根元素,更多说明

Class 组件

  1. class Welcome extends React.Component {
  2. render() {
  3. return <h1>{this.props.name}</h1>;
  4. }
  5. }

Class 组件 API

额外的 API

:- -
this.forceUpdate() 强制重新渲染
this.setState({ ... }) 更新状态
this.setState(state =>{ ... }) 更新状态

属性

:- -
defaultProps 默认 props
displayName 显示组件名称(用于调试)

实例属性

:- -
this.props 组件接受参数
this.state 组件内状态

Pure 组件

  1. import React, {PureComponent} from 'react'
  2. class MessageBox extends PureComponent {
  3. ···
  4. }

高阶组件

  1. import React, { Component } from 'react';
  2. // 高阶组件 with
  3. const with = data => WrappedComponent => {
  4. return class extends Component {
  5. constructor(props) {
  6. super(props);
  7. }
  8. render() {
  9. return (
  10. <WrappedComponent data={data} />
  11. )
  12. }
  13. }
  14. }

使用高阶组件

  1. const LowComponent = (props) => (
  2. <div>{props.data}</div>
  3. );
  4. const MyComp = with('Hello')(LowComponent)

包含关系

  1. function FancyBorder(props) {
  2. return (
  3. <div className={'Fancy'+props.color}>
  4. {props.children}
  5. </div>
  6. );
  7. }

组件可以通过 JSX 嵌套

  1. function WelcomeDialog() {
  2. return (
  3. <FancyBorder color="blue">
  4. <h1 className="title">欢迎</h1>
  5. <p className="message">
  6. 感谢您访问我们的宇宙飞船
  7. </p>
  8. </FancyBorder>
  9. );
  10. }

作为参数传递

  1. function SplitPane(props) {
  2. return (
  3. <div className="SplitPane">
  4. <div className="left">
  5. {props.left}
  6. </div>
  7. <div className="right">
  8. {props.right}
  9. </div>
  10. </div>
  11. );
  12. }
  13. function App() {
  14. return (
  15. <SplitPane
  16. left={<Contacts />}
  17. right={<Chat />}
  18. />
  19. );
  20. }

给组件 SplitPane 传递 leftright 两个组件参数

嵌入内部组件

```jsx {2} import React from ‘react’; import UserAvatar from “./UserAvatar”;

export default function UserProfile() { return (

); }

  1. 注意:假设 `UserAvatar` `UserAvatar.js` 中声明
  2. ### 嵌入外部组件
  3. ```jsx {2}
  4. import React from 'react';
  5. import {Button} from 'uiw';
  6. export default function UserProfile() {
  7. return (
  8. <div className="UserProfile">
  9. <Button type="primary">
  10. 主要按钮
  11. </Button>
  12. </div>
  13. );
  14. }

注意:uiw 组件在 npmjs.com 上找到,需要先安装导入

点组件语法技巧

  1. const Menu = ({ children }) => (
  2. <div className="menu">{children}<div>
  3. );
  4. Menu.Item = ({ children }) => (
  5. <div>{children}<div>
  6. );

  1. <Menu>
  2. <Menu.Item>菜单一</Menu.Item>
  3. <Menu.Item>菜单二</Menu.Item>
  4. <Menu>

Hooks

Hooks API 参考

基础 Hook

方法 描述
useState 返回一个 state,更新 state 的函数 #
useEffect 可能有副作用代码的函数 #
useContext 接收并返回该 context 的当前值 #

额外的 Hook

方法 描述
useReducer useState 的替代方案 #
useCallback 返回一个回调函数 #
useMemo 返回一个 memoized#
useRef 返回一个可变的 ref 对象 #
useImperativeHandle 暴露给父组件的实例值 #
useLayoutEffect DOM 变更后同步调用函数 #
useDebugValue 开发者工具中显示标签 #
useDeferredValue 接受并返回该值的新副本 #
useTransition 过渡任务的等待状态 #
useId 用于生成唯一 ID #

Library Hooks

方法 描述
useSyncExternalStore 读取和订阅外部数据源 #
useInsertionEffect DOM 突变之前 同步触发 #

函数式更新

  1. function Counter({ initialCount }) {
  2. const [count, setCount] = useState(initialCount);
  3. return (
  4. <>
  5. Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button>
  6. <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
  7. <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
  8. </>
  9. );
  10. }

useRef

  1. function TextInputWithFocusButton() {
  2. const $input = useRef(null);
  3. const onButtonClick = () => {
  4. $input.current.focus();
  5. };
  6. return (
  7. <>
  8. <input ref={$input} type="text" />
  9. <button onClick={onButtonClick}>
  10. 聚焦输入
  11. </button>
  12. </>
  13. );
  14. }

current 指向已挂载到 DOM 上的文本输入元素

useImperativeHandle

  1. function FancyInput(props, ref) {
  2. const inputRef = useRef();
  3. useImperativeHandle(ref, () => ({
  4. focus: () => {
  5. inputRef.current.focus();
  6. }
  7. }));
  8. return <input ref={inputRef} />;
  9. }
  10. FancyInput = forwardRef(FancyInput);

父组件使用

  1. <FancyInput ref={inputRef} />
  2. inputRef.current.focus()

useEffect

  1. useEffect(() => {
  2. const subs = props.source.subscribe();
  3. return () => {
  4. subs.unsubscribe();
  5. };
  6. }, [props.source]);

useCallback

  1. const memoizedCallback = useCallback(
  2. () => {
  3. doSomething(a, b);
  4. },
  5. [a, b],
  6. );

useMemo

  1. const memoizedValue = useMemo(
  2. () => {
  3. return computeExpensiveValue(a, b)
  4. },
  5. [a, b]
  6. );

useId

  1. function Checkbox() {
  2. const id = useId();
  3. return (
  4. <>
  5. <label htmlFor={id}>
  6. 你喜欢React吗?
  7. </label>
  8. <input id={id} type="checkbox" />
  9. </>
  10. );
  11. };

用于生成跨服务端和客户端稳定的唯一 ID 的同时避免 hydration 不匹配

useDebugValue

  1. function useFriendStatus(friendID) {
  2. const [
  3. isOnline, setIsOnline
  4. ] = useState(null);
  5. // ...
  6. // 在开发者工具中的这个 Hook 旁边显示标签
  7. // e.g. "FriendStatus: Online"
  8. useDebugValue(
  9. isOnline ? 'Online' : 'Offline'
  10. );
  11. return isOnline;
  12. }

不推荐你向每个自定义 Hook 添加 debug

componentDidMount & componentWillUnmount

  1. useEffect(
  2. () => {
  3. // componentDidMount
  4. // 组件挂载时,可以在这里完成你的任务
  5. return () => {
  6. // componentWillUnmount
  7. // 卸载时执行,清除 effect
  8. };
  9. },
  10. [ ]
  11. );

这是一个类似 class 组件中 componentDidMount & componentWillUnmount 两个生命周期函数的写法。

生命周期

挂载

方法 描述
constructor (props) 渲染前 #
static getDerivedStateFromProps() 调用 render 方法之前调用 #
render() class 组件中唯一必须实现的方法 #
componentDidMount() 在组件挂载后(插入 DOM 树中)立即调用 #
UNSAFE_componentWillMount() 在挂载之前被调用,建议使用 constructor() #

constructor() 上设置初始状态。在 componentDidMount() 上添加 DOM 事件处理程序、计时器(等),然后在 componentWillUnmount() 上删除它们。

卸载

方法 描述
componentWillUnmount() 在组件卸载及销毁之前直接调用 #

过时 API

过时方法 新方法
componentWillMount() UNSAFE_componentWillMount() #
componentWillReceiveProps() UNSAFE_componentWillReceiveProps() #
componentWillUpdate() UNSAFE_componentWillUpdate() #

17+ 之后不再支持,在 17 版本之后,只有新的 UNSAFE_ 生命周期名称可以使用。

更新

方法 描述
static getDerivedStateFromProps(props, state) 调用 render 之前调用,在初始挂载及后续更新时都会被调用 #
shouldComponentUpdate(nextProps, nextState) 如果返回 false,则跳过 render() #
render() 在不修改组件 state 的情况下,每次调用时都返回相同的结果 #
getSnapshotBeforeUpdate() 在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置) #
componentDidUpdate() 这里使用 setState(),但记得比较 props。首次渲染不会执行此方法 #

错误处理

方法 描述
static getDerivedStateFromError(error) 后代组件抛出错误后被调用,它将抛出的错误作为参数,并返回一个值以更新 state #
componentDidCatch(error, info) 在后代组件抛出错误后被调用,会在“提交”阶段被调用,因此允许执行副作用 #

render()

```jsx {2} class Welcome extends React.Component { render() { return

Hello, {this.props.name}

; } }

  1. ### constructor()
  2. ```jsx {1}
  3. constructor(props) {
  4. super(props);
  5. // 不要在这里调用 this.setState()
  6. this.state = { counter: 0 };
  7. this.handleClick = this.handleClick.bind(this);
  8. }

static getDerivedStateFromError()

```jsx {7,13} class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; }

static getDerivedStateFromError(error) { // 更新 state 使下一次渲染可以显降级 UI return { hasError: true }; }

render() { if (this.state.hasError) { // 你可以渲染任何自定义的降级 UI return

Something went wrong.

; }

  1. return this.props.children;

} }

  1. ### componentDidUpdate()
  2. ```jsx {1}
  3. componentDidUpdate(prevProps) {
  4. // 典型用法(不要忘记比较 props):
  5. if (this.props.uid !== prevProps.uid) {
  6. this.fetchData(this.props.uid);
  7. }
  8. }

getSnapshotBeforeUpdate()

  1. getSnapshotBeforeUpdate(prevProps, prevState) {
  2. // 我们是否在 list 中添加新的 items ?
  3. // 捕获滚动​​位置以便我们稍后调整滚动位置。
  4. if (prevProps.list.length < this.props.list.length) {
  5. const list = this.listRef.current;
  6. return list.scrollHeight - list.scrollTop;
  7. }
  8. return null;
  9. }

PropTypes 属性类型检查

PropTypes

  1. import PropTypes from 'prop-types'

:- -
any 任意类型
(props, propName, 组件名称)=>{} 自定义验证器

基础

:- -
string 字符串
number 数组
func 函数
bool 布尔值
symbol -

枚举 Enum

:- -
oneOf(any) 枚举类型
oneOfType([type]) 几种类型中的任意一个类型

数组 Array

:- -
array 数组
arrayOf 数组由某一类型的元素组成

对象 Object

:- -
object 对象
objectOf 对象由某一类型的值组成
instanceOf(...) 类的实例
shape 对象由特定的类型值组成
exact 有额外属性警告

元素 Elements

:- -
element React 元素
elementType React 元素类型(即 MyComponent)
node DOM 节点

必需的

:- -
(···).isRequired 必需的

请参阅:使用 PropTypes 进行类型检查

基本类型

  1. MyComponent.propTypes = {
  2. email: PropTypes.string,
  3. seats: PropTypes.number,
  4. callback: PropTypes.func,
  5. isClosed: PropTypes.bool,
  6. any: PropTypes.any
  7. symbol: PropTypes.symbol,
  8. }

你可以将属性声明为 JS 原生类型,默认都是可选的。

必需的

  1. MyComponent.propTypes = {
  2. // 确保这个 prop 没有被提供时,会打印警告信息
  3. requiredFunc: PropTypes.func.isRequired,
  4. // 任意类型的必需数据
  5. requiredAny: PropTypes.any.isRequired,
  6. }

你可以在任何 PropTypes 属性后面加上 isRequired

枚举

  1. MyComponent.propTypes = {
  2. // 只能是特定的值,枚举类型。
  3. optionalEnum: PropTypes.oneOf([
  4. 'News', 'Photos'
  5. ]),
  6. // 一个对象可以是几种类型中的任意一个类型
  7. optionalUnion: PropTypes.oneOfType([
  8. PropTypes.string,
  9. PropTypes.number,
  10. PropTypes.instanceOf(Message)
  11. ]),
  12. }

元素 Elements

  1. MyComponent.propTypes = {
  2. // 任何可被渲染的元素
  3. // (包括数字、字符串、元素或数组)
  4. // (或 Fragment) 也包含这些类型。
  5. node: PropTypes.node,
  6. // 一个 React 元素。
  7. element: PropTypes.element,
  8. // 一个 React 元素类型(即,MyComponent)
  9. elementType: PropTypes.elementType,
  10. }

对象 Object

  1. MyComponent.propTypes = {
  2. // 可以指定一个对象由某一类型的值组成
  3. objectOf: PropTypes.objectOf(
  4. PropTypes.number
  5. ),
  6. // 可以指定一个对象由特定的类型值组成
  7. objectWithShape: PropTypes.shape({
  8. color: PropTypes.string,
  9. fontSize: PropTypes.number
  10. }),
  11. // 带有额外属性警告的对象
  12. objectWithStrictShape: PropTypes.exact({
  13. name: PropTypes.string,
  14. quantity: PropTypes.number
  15. }),
  16. }

自定义验证器

  1. MyComponent.propTypes = {
  2. custom: (props, propName, compName) => {
  3. if (!/matchm/.test(props[propName])) {
  4. // 它在验证失败时应返回一个 Error 对象
  5. return new Error(
  6. '无效的prop `'
  7. ` \`${propName}\` 提供给` +
  8. ` \`${compName}\`。验证失败。`
  9. );
  10. }
  11. },
  12. }

请不要使用 console.warn 或抛出异常,因为这在 oneOfType 中不会起作用。

自定义的 arrayOfobjectOf 验证器

  1. MyComponent.propTypes = {
  2. arrayProp: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
  3. if (!/matchme/.test(propValue[key])) {
  4. // 它应该在验证失败时返回一个 Error 对象。
  5. return new Error(
  6. 'Invalid prop `' + propFullName + '` supplied to' +
  7. ' `' + componentName + '`. Validation failed.'
  8. );
  9. }
  10. })
  11. }

propValue 是数组或对象本身,key 是他们当前的键。

数组

  1. MyComponent.propTypes = {
  2. arr: PropTypes.arrayOf(PropTypes.number),
  3. };

可以指定一个数组由某一类型的元素组成

验证类的实例

  1. MyComponent.propTypes = {
  2. message: PropTypes.instanceOf(Message),
  3. };

声明 message 为类的实例

另见