天天看點

React 最常用的函數(備忘查詢)

介紹

React 是一個用于建構使用者界面的 JavaScript 庫。

  • React 官方文檔 (reactjs.org)
  • Styled Components 備忘清單 (jaywcjlove.github.io)
import {createRoot} from 'react-dom/client'
import App from './App'
           
const elm = document.getElementById('app')
const root = createRoot(elm);
root.render(<App />);
           

快速建立React項目 (CRA)

npx create-react-app my-app
           

導入多個導出

import React, {Component} from 'react'
import ReactDOM from 'react-dom'
           
export class Hello extends Component {
  ...
}
export default function World() {
  /* ... */
}
           

使用 export 導出 Hello,export default 導出 World 元件

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

使用 import 導入 Hello 元件,在示例中使用。

React 元件中的 CSS

import React from "react";
import "./Student.css";

export const Student = (
  <div className="Student"></div>
);
           

注意:類屬性 className

const divStyle = {
  backgroundImage: 'url(' + imgUrl + ')',
};
export const Student = (
  <div style={divStyle}></div>
);
           

屬性

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

函數元件 Student 中通路屬性

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

Class 元件 Student 中通路屬性

class Student extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
           

class 元件使用 this.props 通路傳遞給元件的屬性。

Children

function Example() {
  return (
    <AlertBox>
      <h1>您有待處理的通知</h1>
    </AlertBox>
  )
}
           

函數 AlertBox 元件

function AlertBox(props) {
  return (
    <div className="alert-box">
      {props.children}
    </div>
  );
}
           
{props.children}
           

Class AlertBox 元件,與函數元件 AlertBox 元件相同

class AlertBox extends React.Component {
  render () {
    return (
      <div className="alert-box">
        {this.props.children}
      </div>
    );
  }
}
           
{this.props.children}
           

children 作為子元件的的屬性傳遞。

State

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

import { useState } from 'react';

function Student() {
  const [count, setCount] = useState(0);
  const click = () => setCount(count + 1);
  return (
    <div>
      <p>您點選了 {count} 次</p>
      <button onClick={click}>
        點選我
      </button>
    </div>
  );
}
           

使用 setState 更新狀态,下面是函數元件讀取狀态

<p>您點選了 {count} 次</p>
           

Class 中的 State

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 (
      <div>
        <button onClick={this.click}>
          點選我
        </button>
        <p>您點選了{this.state.count}次</p>
      </div>
    );
  }
}
           

使用 setState 更新狀态,class 元件中不能使用 hooks。下面是 class 元件讀取狀态

<p>您點選了{this.state.count}次</p>
           

循環

const elm = ['one', 'two', 'three'];
function Student() {
  return (
    <ul>
      {elm.map((value, index) => (
        <li key={index}>{value}</li>
      ))}
    </ul>
  );
}
           

key 值在兄弟節點之間必須唯一

事件監聽

export default function Hello() {
  function handleClick(event) {
    event.preventDefault();
    alert("Hello World");
  }

  return (
    <a href="/" onClick={handleClick}>
      Say Hi
    </a>
  );
}
           

函數注入

function addNumbers(x1, x2) {
  return x1 + x2;
}

const element = (
  <div>
    {addNumbers(2, 5)}
  </div>
);
           

嵌套

import { useState } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';

function Student() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <Avatar src={count} />
      <Profile username={count} />
    </div>
  );
}
           

Portals

React 并_沒有_建立一個新的 div。它隻是把子元素渲染到 domNode 中。domNode 是一個可以在任何位置的有效 DOM 節點。

render() {
  return ReactDOM.createPortal(
    this.props.children,
    domNode
  );
}
           

提供了一種将子節點渲染到存在于父元件以外的 DOM 節點的優秀的方案

Fragment

import { Fragment } from 'react'
import Avatar from './Avatar';
import Profile from './Profile';

const Student = () => (
  <Fragment>
    <Avatar src="./demo.jpg" />
    <Profile username="name" />
  </Fragment>
);
           

從 v16.2.0 開始 Fragment 可用于傳回多個子節點,而無需向 DOM 添加額外的包裝節點。或者使用 <></> 效果是一樣的。

const Student = () => (
  <>
    <Avatar src="./demo.jpg" />
    <Profile username="name" />
  </>
);
           

檢視: Fragments & strings

傳回字元串

render() {
  return 'Look ma, no spans!';
}
           

您可以隻傳回一個字元串。檢視: Fragments & strings

傳回數組

const Student = () => [
  <li key="A">First item</li>,
  <li key="B">Second item</li>
];
           

不要忘記 key!檢視: Fragments & strings

Refs 轉發

const FancyButton = React.forwardRef(
  (props, ref) => (
    <button ref={ref} className="btn">
      {props.children}
    </button>
  )
);
           

使用

// 你可以直接擷取 DOM button 的 ref:
const ref = React.createRef();

<FancyButton ref={ref}>
  點選我
</FancyButton>;
           

Class 元件内部使用 ref 屬性

import {Component,createRef} from 'react'

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

  render() {
    return <div ref={this.myRef} />;
  }
}
           

提示:Refs 适用于類元件,但不适用于函數元件(除非您使用 useRef hook,請參閱hooks)

函數元件内部使用 ref 屬性

function CustomTextInput(props) {
  // 這裡必須聲明 $input,這樣 ref 才可以引用它
  const $input = useRef(null);
  function handleClick() {
    $input.current.focus();
  }
  return (
    <div>
      <input type="text" ref={$input} />
      <input
        type="button" value="聚焦文本輸入"
        onClick={handleClick}
      />
    </div>
  );
}
           

嚴格模式 StrictMode

<div>
  <Header />
  <React.StrictMode>
    <div>
      <ComponentOne />
      <ComponentTwo />
    </div>
  </React.StrictMode>
  <Footer />
</div>
           
  • 識别不安全的生命周期
  • 關于使用過時字元串 ref API 的警告
  • 關于使用廢棄的 findDOMNode 方法的警告
  • 檢測意外的副作用
  • 檢測過時的 context API
  • 確定可複用的狀态

突出顯示應用程式中潛在問題的工具。請參閱:嚴格模式

Profiler

測量一個 React 應用多久渲染一次以及渲染一次的 代價

<Profiler id="Navigation" onRender={callback}>
  <Navigation {...props} />
</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

class CustomButton extends React.Component {
  // ...
}
CustomButton.defaultProps = {
  color: 'blue'
};
           

使用

<CustomButton /> ;
           

不傳值 props.color 将自動設定為 blue

Class 元件預設 state

class Hello extends Component {
  constructor (props) {
    super(props)
    this.state = { visible: true }
  }
}
           

在構造 constructor()中設定預設狀态。

class Hello extends Component {
  state = { visible: true }
}
           

函數元件預設 props

function CustomButton(props) {
  const { color = 'blue' } = props;
  return <div>{color}</div>
}
           

函數元件預設 state

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

JSX

介紹

JSX 僅僅隻是 React.createElement(component, props, ...children) 函數的文法糖

<MyButton color="blue" shadowSize={2}>
  點選我
</MyButton>
           

會編譯為

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  '點選我'
);
           

沒有子節點

<div className="sidebar" />
           

會編譯為

React.createElement(
  'div',
  {className: 'sidebar'}
)
           

JSX 點文法

const Menu = ({ children }) => (
  <div className="menu">{children}<div>
);

Menu.Item = ({ children }) => (
  <div>{children}<div>
);

<Menu>
  <Menu.Item>菜單一</Menu.Item>
  <Menu.Item>菜單二</Menu.Item>
<Menu>
           

JSX Element

let element = <h1>Hello, world!</h1>;
let emptyHeading = <h1 />;

const root = ReactDOM.createRoot(
  document.getElementById('root')
);

const element = <h1>Hello, world</h1>;
root.render(element);
           

參考:渲染元素

JSX 屬性

const avatarUrl = "img/picture.jpg"
const element = <img src={avatarUrl} />;

const element = (
  <button className="btn">
    點選我
  </button>
);
           

注意:類屬性 className

JSX 表達式

let name = '張三';
let element = <h1>Hello, {name}</h1>;

function fullName(firstName, lastName) {
  return firstName + ' ' + lastName;
}
let element = (
  <h1>
    Hello, {fullName('三', '張')}
  </h1>
);
           

JSX style

const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};
function MyComponent() {
  return <div style={divStyle}>元件</div>;
}
           

JSX dangerouslySetInnerHTML

const markup = {__html: '我 · 你' };

const MyComponent = () => (
  <div dangerouslySetInnerHTML={markup} />
);
           

dangerouslySetInnerHTML 是 React 為浏覽器 DOM 提供 innerHTML 的替換方案。

JSX htmlFor

const MyComponent = () => (
  <div>
    <input type="radio" id="ab" name="v">
    <label for="ab">HTML</label>
  </div>
);
           

for 在 JS 中是保留字,JSX 元素使用了 htmlFor 代替

JSX defaultValue

非受控元件的屬性,設定元件第一次挂載時的 value

<textarea defaultValue="Hello" />
           

<input>、<select> 和 <textarea> 支援 value 屬性

JSX defaultChecked

非受控元件的屬性,設定元件是否被選中

<input type="radio" defaultChecked />
           

類型為 checkbox 或 radio 時,元件支援 checked 屬性

JSX className

屬性用于指定 CSS 的 class

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

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

JSX 條件渲染

import React from "react";

function formatName(user) {
  return user.firstName 
    + ' ' 
    + user.lastName;
}

export function Greeting(user) {
  if (user) {
    return (
      <h1>你好, {formatName(user)}!</h1>
    );
  }
  return (
    <h1>你好, 先生。</h1>
  );
}
           

注意:元件必須總是傳回一些東西。

使用

<Greeting firstName="三" lastName="張" />
           

JSX 三目運算符 / 與運算符 &&

export default function Weather(props) {
  const isLoggedIn = props.isLoggedIn;
  return (
    <div>
      <b>{isLoggedIn ? '已' : '未'}</b>登入。
    </div>
  );
}
           
{isShow && <div>内容</div>}
           

JSX 元件

<Dropdown>
  下拉清單
  <Menu>
    <Menu.Item>菜單一</Menu.Item>
    <Menu.Item>菜單二</Menu.Item>
    <Menu.Item>菜單三</Menu.Item>
  </Menu>
</Dropdown>
           

元件名稱以大駝峰式命名。

JSX 元素變量

function Greeting(props) {
  let button;
  if (props.isLoggedIn) {
    button = <UserGreeting />;
  } else {
    button = <GuestGreeting />;
  }
  return <div>{button}</div>;
}
           

JSX 注釋

function Student() {
  const [count, setCount] = useState(0);
  return (
    <Fragment>
      {/* 這裡寫注釋 */}
    </Fragment>
  );
}
           

元件

函數元件

import React from 'react';

const UserName = () => <h1>Kenny</h1>;

export default function UserProfile() {
  return (
    <div className="UserProfile">
      <div>Hello</div>  
      <UserName />
    </div>
  );
}
           

注意:每個元件都需要一個根元素,更多說明。

Class 元件

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

Class 元件 API

額外的 API

this.forceUpdate() 強制重新渲染
this.setState({ ... }) 更新狀态
this.setState(state =>{ ... }) 更新狀态

屬性

defaultProps 預設 props
displayName 顯示元件名稱(用于調試)

執行個體屬性

this.props 元件接受參數
this.state 元件内狀态

Pure 元件

import React, {PureComponent} from 'react'

class MessageBox extends PureComponent {
  ···
}
           

高階元件

import React, { Component } from 'react';
// 高階元件 with
const with = data => WrappedComponent => {
  return class extends Component {
    constructor(props) {
      super(props);
    }
    render() {
      return (
        <WrappedComponent data={data} />
      )
    }
  }
}
           

使用高階元件

const LowComponent = (props) => (
  <div>{props.data}</div>
);

const MyComp = with('Hello')(LowComponent)
           

包含關系

function FancyBorder(props) {
  return (
    <div className={'Fancy'+props.color}>
      {props.children}
    </div>
  );
}
           

元件可以通過 JSX 嵌套

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="title">歡迎</h1>
      <p className="message">
        感謝您通路我們的宇宙飛船
      </p>
    </FancyBorder>
  );
}
           

作為參數傳遞

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="left">
        {props.left}
      </div>
      <div className="right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={<Contacts />}
      right={<Chat />}
    />
  );
}
           

給元件 SplitPane 傳遞 left 和 right 兩個元件參數

嵌入内部元件

import React from 'react';
import UserAvatar from "./UserAvatar";

export default function UserProfile() {
  return (
    <div className="UserProfile">
      <UserAvatar />
      <UserAvatar />
    </div>
  );
}
           

注意:假設 UserAvatar 在 UserAvatar.js 中聲明

嵌入外部元件

import React from 'react';
import {Button} from 'uiw';
export default function UserProfile() {
  return (
    <div className="UserProfile">
      <Button type="primary">
        主要按鈕
      </Button>
    </div>
  );
}
           

注意:uiw 元件在 npmjs.com 上找到,需要先安裝導入

點元件文法技巧

const Menu = ({ children }) => (
  <div className="menu">{children}<div>
);

Menu.Item = ({ children }) => (
  <div>{children}<div>
);
           
<Menu>
  <Menu.Item>菜單一</Menu.Item>
  <Menu.Item>菜單二</Menu.Item>
<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 突變之前 同步觸發 #

函數式更新

function Counter({ initialCount }) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
    </>
  );
}
           

useRef

function TextInputWithFocusButton() {
  const $input = useRef(null);
  const onButtonClick = () => {
    $input.current.focus();
  };
  return (
    <>
      <input ref={$input} type="text" />
      <button onClick={onButtonClick}>
        聚焦輸入
      </button>
    </>
  );
}
           

current 指向已挂載到 DOM 上的文本輸入元素

useImperativeHandle

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} />;
}
FancyInput = forwardRef(FancyInput);
           

父元件使用

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

useEffect

useEffect(() => {
  const subs = props.source.subscribe();
  return () => {
    subs.unsubscribe();
  };
}, [props.source]);
           

useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
           

useMemo

const memoizedValue = useMemo(
  () => {
    return computeExpensiveValue(a, b)
  },
  [a, b]
);
           

useId

function Checkbox() {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>
        你喜歡React嗎?
      </label>
      <input id={id} type="checkbox" />
    </>
  );
};
           

用于生成跨服務端和用戶端穩定的唯一 ID 的同時避免 hydration 不比對

useDebugValue

function useFriendStatus(friendID) {
  const [
    isOnline, setIsOnline
  ] = useState(null);
  // ...
  // 在開發者工具中的這個 Hook 旁邊顯示标簽
  // e.g. "FriendStatus: Online"
  useDebugValue(
    isOnline ? 'Online' : 'Offline'
  );
  return isOnline;
}
           

不推薦你向每個自定義 Hook 添加 debug 值

componentDidMount & componentWillUnmount

useEffect(
  () => {
    // componentDidMount
    // 元件挂載時,可以在這裡完成你的任務
    return () => {
      // componentWillUnmount
      // 解除安裝時執行,清除 effect
    };
  },
  [ ]
);
           

這是一個類似 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()

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
           

constructor()

constructor(props) {
  super(props);
  // 不要在這裡調用 this.setState()
  this.state = { counter: 0 };
  this.handleClick = this.handleClick.bind(this);
}
           

static getDerivedStateFromError()

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 <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}
           

componentDidUpdate()

componentDidUpdate(prevProps) {
  // 典型用法(不要忘記比較 props):
  if (this.props.uid !== prevProps.uid) {
    this.fetchData(this.props.uid);
  }
}
           

getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate(prevProps, prevState) {
  // 我們是否在 list 中添加新的 items ?
  // 捕獲滾動位置以便我們稍後調整滾動位置。
  if (prevProps.list.length < this.props.list.length) {
    const list = this.listRef.current;
    return list.scrollHeight - list.scrollTop;
  }
  return null;
}
           

PropTypes 屬性類型檢查

PropTypes

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 進行類型檢查

基本類型

MyComponent.propTypes = {
  email:      PropTypes.string,
  seats:      PropTypes.number,
  callback:   PropTypes.func,
  isClosed:   PropTypes.bool,
  any:        PropTypes.any
  symbol:     PropTypes.symbol,
}
           

你可以将屬性聲明為 JS 原生類型,預設都是可選的。

必需的

MyComponent.propTypes = {
  // 確定這個 prop 沒有被提供時,會列印警告資訊
  requiredFunc: PropTypes.func.isRequired,

  // 任意類型的必需資料
  requiredAny: PropTypes.any.isRequired,
}
           

你可以在任何 PropTypes 屬性後面加上 isRequired。

枚舉

MyComponent.propTypes = {
  // 隻能是特定的值,枚舉類型。
  optionalEnum: PropTypes.oneOf([
    'News', 'Photos'
  ]),
  // 一個對象可以是幾種類型中的任意一個類型
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),
}
           

元素 Elements

MyComponent.propTypes = {
  // 任何可被渲染的元素
  // (包括數字、字元串、元素或數組)
  // (或 Fragment) 也包含這些類型。
  node: PropTypes.node,

  // 一個 React 元素。
  element: PropTypes.element,

  // 一個 React 元素類型(即,MyComponent)
  elementType: PropTypes.elementType,
}
           

對象 Object

MyComponent.propTypes = {
  // 可以指定一個對象由某一類型的值組成
  objectOf: PropTypes.objectOf(
    PropTypes.number
  ),
  // 可以指定一個對象由特定的類型值組成
  objectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),
  // 帶有額外屬性警告的對象
  objectWithStrictShape: PropTypes.exact({
    name: PropTypes.string,
    quantity: PropTypes.number
  }),
}
           

自定義驗證器

MyComponent.propTypes = {
  custom: (props, propName, compName) => {
    if (!/matchm/.test(props[propName])) {
      // 它在驗證失敗時應傳回一個 Error 對象
      return new Error(
        '無效的prop `'
        ` \`${propName}\` 提供給` + 
        ` \`${compName}\`。驗證失敗。`
      );

    }
  },
}
           

請不要使用 console.warn 或抛出異常,因為這在 oneOfType 中不會起作用。

自定義的arrayOf或objectOf驗證器

MyComponent.propTypes = {
  arrayProp: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
    if (!/matchme/.test(propValue[key])) {
      // 它應該在驗證失敗時傳回一個 Error 對象。
      return new Error(
        'Invalid prop `' + propFullName + '` supplied to' +
        ' `' + componentName + '`. Validation failed.'
      );
    }
  })
}
           

propValue 是數組或對象本身,key 是他們目前的鍵。

數組

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

可以指定一個數組由某一類型的元素組成

驗證類的執行個體

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

聲明 message 為類的執行個體

React 官方中文文檔 (zh-hans.reactjs.org)

繼續閱讀