适合初学者的综合 React 备忘清单
React 是一个用于构建用户界面的 JavaScript 库
- React 官方文档(reactjs.org)
- Styled Components 备忘清单(jaywcjlove.github.io)
- TypeScript JSX 备忘清单(jaywcjlove.github.io)
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-appimportReact,{Component}from'react'importReactDOMfrom'react-dom'exportclassHelloextendsComponent{
...
}exportdefaultfunctionWorld(){/* ... */}使用 export 导出 Hello,export default 导出 World 组件
importWorld,{Hello}from'./hello.js';使用 import 导入 Hello 组件,在示例中使用。
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 访问传递给组件的属性。
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,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>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>);}React 并_没有_创建一个新的 div。它只是把子元素渲染到 domNode 中。domNode 是一个可以在任何位置的有效 DOM 节点。
render(){returnReactDOM.createPortal(this.props.children,domNode);}提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案
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"/></>);render(){return'Look ma, no spans!';}您可以只返回一个字符串。查看: Fragments & strings
constStudent=()=>[<likey="A">First item</li>,<likey="B">Second item</li>];不要忘记 key!查看: Fragments & strings
constFancyButton=React.forwardRef((props,ref)=>(<buttonref={ref}className="btn">{props.children}</button>));// 你可以直接获取 DOM button 的 ref:constref=React.createRef();<FancyButtonref={ref}>
点击我
</FancyButton>;import{Component,createRef}from'react'classMyComponentextendsComponent{constructor(props){super(props);this.myRef=createRef();}render(){return<divref={this.myRef}/>;}}提示:Refs 适用于类组件,但不适用于函数组件(除非您使用 useRef hook,请参阅hooks)
functionCustomTextInput(props){// 这里必须声明 $input,这样 ref 才可以引用它const$input=useRef(null);functionhandleClick(){$input.current.focus();}return(<div><inputtype="text"ref={$input}/><inputtype="button"value="聚焦文本输入"onClick={handleClick}/></div>);}<div><Header/><React.StrictMode><div><ComponentOne/><ComponentTwo/></div></React.StrictMode><Footer/></div>突出显示应用程序中潜在问题的工具。请参阅:严格模式
测量一个 React 应用多久渲染一次以及渲染一次的 代价
<Profilerid="Navigation"onRender={callback}><Navigation{...props}/></Profiler>为了分析 Navigation 组件和它的子代。应该在需要时才去使用它。
| :- | :- |
|---|---|
id(string) | 发生提交的 Profiler 树的 id |
onRender(function) | 组件树任何组件 “提交” 一个更新的时候调用这个函数 |
| :- | :- |
|---|---|
phase: "mount" | "update" | 判断是由 props/state/hooks 改变 或 “第一次装载” 引起的重渲染 |
actualDuration: number | 本次更新在渲染 Profiler 和它的子代上花费的时间 |
baseDuration: number | 在 Profiler 树中最近一次每一个组件 render 的持续时间 |
startTime: number | 本次更新中 React 开始渲染的时间戳 |
commitTime: number | 本次更新中 React commit 阶段结束的时间戳 |
interactions: Set | 当更新被制定时,“interactions” 的集合会被追踪 |
classCustomButtonextendsReact.Component{// ...}CustomButton.defaultProps={color: 'blue'};<CustomButton/>;不传值 props.color 将自动设置为 blue
classHelloextendsComponent{constructor(props){super(props)this.state={visible: true}}}在构造 constructor()中设置默认状态。
classHelloextendsComponent{state={visible: true}}functionCustomButton(props){const{ color ='blue'}=props;return<div>{color}</div>}functionCustomButton(){const[color,setColor]=useState('blue')return<div>{color}</div>}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'})constMenu=({ children })=>(<divclassName="menu">{children}<div>
);
Menu.Item = ({children}) =>(<div>{children}<div>
);
<Menu><Menu.Item>菜单一</Menu.Item><Menu.Item>菜单二</Menu.Item><Menu>letelement=<h1>Hello, world!</h1>;letemptyHeading=<h1/>;constroot=ReactDOM.createRoot(document.getElementById('root'));constelement=<h1>Hello, world</h1>;root.render(element);参考:渲染元素
constavatarUrl="img/picture.jpg"constelement=<imgsrc={avatarUrl}/>;constelement=(<buttonclassName="btn">
点击我
</button>);注意:类属性 className
letname='张三';letelement=<h1>Hello, {name}</h1>;functionfullName(firstName,lastName){returnfirstName+' '+lastName;}letelement=(<h1>
Hello, {fullName('三','张')}</h1>);constdivStyle={color: 'blue',backgroundImage: 'url('+imgUrl+')',};functionMyComponent(){return<divstyle={divStyle}>组件</div>;}constmarkup={__html: '我 · 你'};constMyComponent=()=>(<divdangerouslySetInnerHTML={markup}/>);dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。
constMyComponent=()=>(<div><inputtype="radio"id="ab"name="v"><labelfor="ab">HTML</label></div>
);for 在 JS 中是保留字,JSX 元素使用了 htmlFor 代替
非受控组件的属性,设置组件第一次挂载时的 value
<textareadefaultValue="Hello"/><input>、<select> 和 <textarea> 支持 value 属性
非受控组件的属性,设置组件是否被选中
<inputtype="radio"defaultChecked/>类型为 checkbox 或 radio 时,组件支持 checked 属性
属性用于指定 CSS 的 class
<divclassName="warp">...</div>React 中使用 Web Components 使用 class 属性代替
importReactfrom"react";functionformatName(user){returnuser.firstName+' '+user.lastName;}exportfunctionGreeting(user){if(user){return(<h1>你好, {formatName(user)}!</h1>);}return(<h1>你好, 先生。</h1>);}注意:组件必须总是返回一些东西。
<GreetingfirstName="三"lastName="张"/>exportdefaultfunctionWeather(props){constisLoggedIn=props.isLoggedIn;return(<div><b>{isLoggedIn ? '已' : '未'}</b>登录。
</div>);}{isShow&&<div>内容</div>}<Dropdown>
下拉列表
<Menu><Menu.Item>菜单一</Menu.Item><Menu.Item>菜单二</Menu.Item><Menu.Item>菜单三</Menu.Item></Menu></Dropdown>组件名称以大驼峰式命名。
functionGreeting(props){letbutton;if(props.isLoggedIn){button=<UserGreeting/>;}else{button=<GuestGreeting/>;}return<div>{button}</div>;}functionStudent(){const[count,setCount]=useState(0);return(<Fragment>{/* 这里写注释 */}</Fragment>);}importReactfrom'react';constUserName=()=><h1>Kenny</h1>;exportdefaultfunctionUserProfile(){return(<divclassName="UserProfile"><div>Hello</div><UserName/></div>);}注意:每个组件都需要一个根元素,更多说明。
classWelcomeextendsReact.Component{render(){return<h1>{this.props.name}</h1>;}}| :- | - |
|---|---|
this.forceUpdate() | 强制重新渲染 |
this.setState({ ... }) | 更新状态 |
this.setState(state =>{ ... }) | 更新状态 |
| :- | - |
|---|---|
defaultProps | 默认 props |
displayName | 显示组件名称(用于调试) |
| :- | - |
|---|---|
this.props | 组件接受参数 |
this.state | 组件内状态 |
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 传递 left 和 right 两个组件参数
importReactfrom'react';importUserAvatarfrom"./UserAvatar";exportdefaultfunctionUserProfile(){return(<divclassName="UserProfile"><UserAvatar/><UserAvatar/></div>);}注意:假设 UserAvatar 在 UserAvatar.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>| 方法 | 描述 |
|---|---|
useState | 返回一个 state,更新 state 的函数 # |
useEffect | 可能有副作用代码的函数 # |
useContext | 接收并返回该 context 的当前值 # |
| 方法 | 描述 |
|---|---|
useReducer | useState 的替代方案 # |
useCallback | 返回一个回调函数 # |
useMemo | 返回一个 memoized 值# |
useRef | 返回一个可变的 ref 对象 # |
useImperativeHandle | 暴露给父组件的实例值 # |
useLayoutEffect | DOM 变更后同步调用函数 # |
useDebugValue | 开发者工具中显示标签 # |
useDeferredValue | 接受并返回该值的新副本 # |
useTransition | 过渡任务的等待状态 # |
useId | 用于生成唯一 ID # |
| 方法 | 描述 |
|---|---|
useSyncExternalStore | 读取和订阅外部数据源 # |
useInsertionEffect | DOM 突变之前 同步触发 # |
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></>);}functionTextInputWithFocusButton(){const$input=useRef(null);constonButtonClick=()=>{$input.current.focus();};return(<><inputref={$input}type="text"/><buttononClick={onButtonClick}>
聚焦输入
</button></>);}current 指向已挂载到 DOM 上的文本输入元素
functionFancyInput(props,ref){constinputRef=useRef();useImperativeHandle(ref,()=>({focus: ()=>{inputRef.current.focus();}}));return<inputref={inputRef}/>;}FancyInput=forwardRef(FancyInput);父组件使用
<FancyInputref={inputRef}/>inputRef.current.focus()useEffect(()=>{constsubs=props.source.subscribe();return()=>{subs.unsubscribe();};},[props.source]);constmemoizedCallback=useCallback(()=>{doSomething(a,b);},[a,b],);constmemoizedValue=useMemo(()=>{returncomputeExpensiveValue(a,b)},[a,b]);functionCheckbox(){constid=useId();return(<><labelhtmlFor={id}>
你喜欢React吗?
</label><inputid={id}type="checkbox"/></>);};用于生成跨服务端和客户端稳定的唯一 ID 的同时避免 hydration 不匹配
functionuseFriendStatus(friendID){const[isOnline,setIsOnline]=useState(null);// ...// 在开发者工具中的这个 Hook 旁边显示标签// e.g. "FriendStatus: Online"useDebugValue(isOnline ? 'Online' : 'Offline');returnisOnline;}不推荐你向每个自定义 Hook 添加 debug 值
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() | 在组件卸载及销毁之前直接调用 # |
| 过时方法 | 新方法 |
|---|---|
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) | 在后代组件抛出错误后被调用,会在“提交”阶段被调用,因此允许执行副作用 # |
classWelcomeextendsReact.Component{render(){return<h1>Hello, {this.props.name}</h1>;}}constructor(props){super(props);// 不要在这里调用 this.setState()this.state={counter: 0};this.handleClick=this.handleClick.bind(this);}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(prevProps){// 典型用法(不要忘记比较 props):if(this.props.uid!==prevProps.uid){this.fetchData(this.props.uid);}}getSnapshotBeforeUpdate(prevProps,prevState){// 我们是否在 list 中添加新的 items ?// 捕获滚动位置以便我们稍后调整滚动位置。if(prevProps.list.length<this.props.list.length){constlist=this.listRef.current;returnlist.scrollHeight-list.scrollTop;}returnnull;}importPropTypesfrom'prop-types'| :- | - |
|---|---|
any | 任意类型 |
(props, propName, 组件名称)=>{} | 自定义验证器 |
| :- | - |
|---|---|
string | 字符串 |
number | 数组 |
func | 函数 |
bool | 布尔值 |
symbol | - |
| :- | - |
|---|---|
oneOf(any) | 枚举类型 |
oneOfType([type]) | 几种类型中的任意一个类型 |
| :- | - |
|---|---|
array | 数组 |
arrayOf | 数组由某一类型的元素组成 |
| :- | - |
|---|---|
object | 对象 |
objectOf | 对象由某一类型的值组成 |
instanceOf(...) | 类的实例 |
shape | 对象由特定的类型值组成 |
exact | 有额外属性警告 |
| :- | - |
|---|---|
element | React 元素 |
elementType | React 元素类型(即 MyComponent) |
node | DOM 节点 |
| :- | - |
|---|---|
(···).isRequired | 必需的 |
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)]),}MyComponent.propTypes={// 任何可被渲染的元素// (包括数字、字符串、元素或数组)// (或 Fragment) 也包含这些类型。node: PropTypes.node,// 一个 React 元素。element: PropTypes.element,// 一个 React 元素类型(即,MyComponent)elementType: PropTypes.elementType,}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 中不会起作用。
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 为类的实例
- React 官方中文文档(zh-hans.reactjs.org)
- 反应生命周期方法图(projects.wojtekmaj.pl)
- React 16 Cheat Sheet
- Awesome React(github.com)