Skip to content

Latest commit

History

History
1541 lines (1209 loc) · 31.9 KB

File metadata and controls

1541 lines (1209 loc) · 31.9 KB

React 备忘清单

NPM versionDownloadsRepo DependentsGithub repo

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

入门

介绍

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

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

constelm=document.getElementById('app')constroot=createRoot(elm);root.render(<App/>);

快速创建 React 项目 (CRA)

npx create-react-app my-app

导入多个导出

importReact,{Component}from'react'importReactDOMfrom'react-dom'

exportclassHelloextendsComponent{
...
}exportdefaultfunctionWorld(){/* ... */}

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

importWorld,{Hello}from'./hello.js';

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

React 组件中的 CSS

importReactfrom"react";import"./Student.css";exportconstStudent=(<divclassName="Student"></div>);

注意:类属性 className

constdivStyle={backgroundImage: 'url('+imgUrl+')',};exportconstStudent=(<divstyle={divStyle}></div>);

属性

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

函数组件 Student 中访问属性

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

Class 组件 Student 中访问属性

classStudentextendsReact.Component{render(){return(<h1>Hello, {this.props.name}</h1>);}}

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

Children

functionExample(){return(<AlertBox><h1>您有待处理的通知</h1></AlertBox>)}

函数 AlertBox 组件

functionAlertBox(props){return(<divclassName="alert-box">{props.children}</div>);}

{props.children}

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

classAlertBoxextendsReact.Component{render(){return(<divclassName="alert-box">{this.props.children}</div>);}}

{this.props.children}

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

State

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

import{useState}from'react';functionStudent(){const[count,setCount]=useState(0);constclick=()=>setCount(count+1);return(<div><p>您点击了 {count}</p><buttononClick={click}>
点击我
</button></div>);}

使用 setState 更新状态,下面是函数组件读取状态

<p>您点击了 {count}</p>

Class 中的 State

importReactfrom'react';classStudentextendsReact.Component{constructor(props){super(props);this.state={count: 1};// 确保函数可以访问组件属性(ES2015)this.click=this.click.bind(this);}click(){constcount=this.state.count;this.setState({count: count+1})}render(){return(<div><buttononClick={this.click}>
点击我
</button><p>您点击了{this.state.count}</p></div>);}}

使用 setState 更新状态,class 组件中不能使用 hooks。下面是 class 组件读取状态

<p>您点击了{this.state.count}</p>

循环

constelm=['one','two','three'];functionStudent(){return(<ul>{elm.map((value,index)=>(<likey={index}>{value}</li>))}</ul>);}

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

事件监听

exportdefaultfunctionHello(){functionhandleClick(event){event.preventDefault();alert("Hello World");}return(<ahref="/"onClick={handleClick}>
Say Hi
</a>);}

函数注入

functionaddNumbers(x1,x2){returnx1+x2;}constelement=(<div>{addNumbers(2,5)}</div>);

嵌套

import{useState}from'react'importAvatarfrom'./Avatar';importProfilefrom'./Profile';functionStudent(){const[count,setCount]=useState(0);return(<div><Avatarsrc={count}/><Profileusername={count}/></div>);}

Portals

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

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

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

Fragment

import{Fragment}from'react'importAvatarfrom'./Avatar';importProfilefrom'./Profile';constStudent=()=>(<Fragment><Avatarsrc="./demo.jpg"/><Profileusername="name"/></Fragment>);

v16.2.0 开始 Fragment 可用于返回多个子节点,而无需向 DOM 添加额外的包装节点。或者使用 <></> 效果是一样的。

constStudent=()=>(<><Avatarsrc="./demo.jpg"/><Profileusername="name"/></>);

查看: Fragments & strings

返回字符串

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

您可以只返回一个字符串。查看: Fragments & strings

返回数组

constStudent=()=>[<likey="A">First item</li>,<likey="B">Second item</li>];

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

Refs 转发

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

使用

// 你可以直接获取 DOM button 的 ref:constref=React.createRef();<FancyButtonref={ref}>
点击我
</FancyButton>;

Class 组件内部使用 ref 属性

import{Component,createRef}from'react'classMyComponentextendsComponent{constructor(props){super(props);this.myRef=createRef();}render(){return<divref={this.myRef}/>;}}

提示:Refs 适用于类组件,但不适用于函数组件(除非您使用 useRef hook,请参阅hooks

函数组件内部使用 ref 属性

functionCustomTextInput(props){// 这里必须声明 $input,这样 ref 才可以引用它const$input=useRef(null);functionhandleClick(){$input.current.focus();}return(<div><inputtype="text"ref={$input}/><inputtype="button"value="聚焦文本输入"onClick={handleClick}/></div>);}

严格模式 StrictMode

<div><Header/><React.StrictMode><div><ComponentOne/><ComponentTwo/></div></React.StrictMode><Footer/></div>

突出显示应用程序中潜在问题的工具。请参阅:严格模式

Profiler

测量一个 React 应用多久渲染一次以及渲染一次的 代价

<Profilerid="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

classCustomButtonextendsReact.Component{// ...}CustomButton.defaultProps={color: 'blue'};

使用

<CustomButton/>;

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

Class 组件默认 state

classHelloextendsComponent{constructor(props){super(props)this.state={visible: true}}}

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

classHelloextendsComponent{state={visible: true}}

函数组件默认 props

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

函数组件默认 state

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

JSX

介绍

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

<MyButtoncolor="blue"shadowSize={2}>
点击我
</MyButton>

会编译为

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

没有子节点

<divclassName="sidebar"/>

会编译为

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

JSX 点语法

constMenu=({ children })=>(<divclassName="menu">{children}<div>
);
Menu.Item = ({children}) =>(<div>{children}<div>
);
<Menu><Menu.Item>菜单一</Menu.Item><Menu.Item>菜单二</Menu.Item><Menu>

JSX Element

letelement=<h1>Hello, world!</h1>;letemptyHeading=<h1/>;constroot=ReactDOM.createRoot(document.getElementById('root'));constelement=<h1>Hello, world</h1>;root.render(element);

参考:渲染元素

JSX 属性

constavatarUrl="img/picture.jpg"constelement=<imgsrc={avatarUrl}/>;constelement=(<buttonclassName="btn">
点击我
</button>);

注意:类属性 className

JSX 表达式

letname='张三';letelement=<h1>Hello, {name}</h1>;functionfullName(firstName,lastName){returnfirstName+' '+lastName;}letelement=(<h1>
Hello, {fullName('三','张')}</h1>);

JSX style

constdivStyle={color: 'blue',backgroundImage: 'url('+imgUrl+')',};functionMyComponent(){return<divstyle={divStyle}>组件</div>;}

JSX dangerouslySetInnerHTML

constmarkup={__html: '我 &middot; 你'};constMyComponent=()=>(<divdangerouslySetInnerHTML={markup}/>);

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

JSX htmlFor

constMyComponent=()=>(<div><inputtype="radio"id="ab"name="v"><labelfor="ab">HTML</label></div>
);

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

JSX defaultValue

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

<textareadefaultValue="Hello"/>

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

JSX defaultChecked

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

<inputtype="radio"defaultChecked/>

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

JSX className

属性用于指定 CSSclass

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

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

JSX 条件渲染

importReactfrom"react";functionformatName(user){returnuser.firstName+' '+user.lastName;}exportfunctionGreeting(user){if(user){return(<h1>你好, {formatName(user)}!</h1>);}return(<h1>你好, 先生。</h1>);}

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

使用

<GreetingfirstName="三"lastName="张"/>

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

exportdefaultfunctionWeather(props){constisLoggedIn=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 元素变量

functionGreeting(props){letbutton;if(props.isLoggedIn){button=<UserGreeting/>;}else{button=<GuestGreeting/>;}return<div>{button}</div>;}

JSX 注释

functionStudent(){const[count,setCount]=useState(0);return(<Fragment>{/* 这里写注释 */}</Fragment>);}

组件

函数组件

importReactfrom'react';constUserName=()=><h1>Kenny</h1>;exportdefaultfunctionUserProfile(){return(<divclassName="UserProfile"><div>Hello</div><UserName/></div>);}

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

Class 组件

classWelcomeextendsReact.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 组件

importReact,{PureComponent}from'react'classMessageBoxextendsPureComponent{···}

高阶组件

importReact,{Component}from'react';// 高阶组件 withconstwith=data=>WrappedComponent=>{returnclassextendsComponent{constructor(props){super(props);}render(){return(<WrappedComponentdata={data}/>)}}}

使用高阶组件

constLowComponent=(props)=>(<div>{props.data}</div>);constMyComp=with('Hello')(LowComponent)

包含关系

functionFancyBorder(props){return(<divclassName={'Fancy'+props.color}>{props.children}</div>);}

组件可以通过 JSX 嵌套

functionWelcomeDialog(){return(<FancyBordercolor="blue"><h1className="title">欢迎</h1><pclassName="message">
感谢您访问我们的宇宙飞船
</p></FancyBorder>);}

作为参数传递

functionSplitPane(props){return(<divclassName="SplitPane"><divclassName="left">{props.left}</div><divclassName="right">{props.right}</div></div>);}functionApp(){return(<SplitPaneleft={<Contacts/>}right={<Chat/>}/>);}

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

嵌入内部组件

importReactfrom'react';importUserAvatarfrom"./UserAvatar";exportdefaultfunctionUserProfile(){return(<divclassName="UserProfile"><UserAvatar/><UserAvatar/></div>);}

注意:假设 UserAvatarUserAvatar.js 中声明

嵌入外部组件

importReactfrom'react';import{Button}from'uiw';exportdefaultfunctionUserProfile(){return(<divclassName="UserProfile"><Buttontype="primary">
主要按钮
</Button></div>);}

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

点组件语法技巧

constMenu=({ children })=>(<divclassName="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

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

Library Hooks

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

函数式更新

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

useRef

functionTextInputWithFocusButton(){const$input=useRef(null);constonButtonClick=()=>{$input.current.focus();};return(<><inputref={$input}type="text"/><buttononClick={onButtonClick}>
聚焦输入
</button></>);}

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

useImperativeHandle

functionFancyInput(props,ref){constinputRef=useRef();useImperativeHandle(ref,()=>({focus: ()=>{inputRef.current.focus();}}));return<inputref={inputRef}/>;}FancyInput=forwardRef(FancyInput);

父组件使用

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

useEffect

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

useCallback

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

useMemo

constmemoizedValue=useMemo(()=>{returncomputeExpensiveValue(a,b)},[a,b]);

useId

functionCheckbox(){constid=useId();return(<><labelhtmlFor={id}>
你喜欢React吗?
</label><inputid={id}type="checkbox"/></>);};

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

useDebugValue

functionuseFriendStatus(friendID){const[isOnline,setIsOnline]=useState(null);// ...// 在开发者工具中的这个 Hook 旁边显示标签// e.g. "FriendStatus: Online"useDebugValue(isOnline ? 'Online' : 'Offline');returnisOnline;}

不推荐你向每个自定义 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()

classWelcomeextendsReact.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()

classErrorBoundaryextendsReact.Component{constructor(props){super(props);this.state={hasError: false};}staticgetDerivedStateFromError(error){// 更新 state 使下一次渲染可以显降级 UIreturn{hasError: true};}render(){if(this.state.hasError){// 你可以渲染任何自定义的降级 UIreturn<h1>Something went wrong.</h1>;}returnthis.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){constlist=this.listRef.current;returnlist.scrollHeight-list.scrollTop;}returnnull;}

PropTypes 属性类型检查

PropTypes

importPropTypesfrom'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

:--
elementReact 元素
elementTypeReact 元素类型(即 MyComponent)
nodeDOM 节点

必需的

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

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

基本类型

MyComponent.propTypes={email: PropTypes.string,seats: PropTypes.number,callback: PropTypes.func,isClosed: PropTypes.bool,any: PropTypes.anysymbol: 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 对象returnnewError('无效的prop `'` \`${propName}\` 提供给`+` \`${compName}\`。验证失败。`);}},}

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

自定义的 arrayOfobjectOf 验证器

MyComponent.propTypes={arrayProp: PropTypes.arrayOf((propValue,key,componentName,location,propFullName)=>{if(!/matchme/.test(propValue[key])){// 它应该在验证失败时返回一个 Error 对象。returnnewError('Invalid prop `'+propFullName+'` supplied to'+' `'+componentName+'`. Validation failed.');}})}

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

数组

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

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

验证类的实例

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

声明 message 为类的实例

另见