一、钩子
1.状态钩子 useState 定义数据
//定义name数据初始值为DG,修改方法名为setName
const [name, setName] = useState('DG')
//调用修改方法,修改name的值为DH
setName('DH')
2.上下文钩子 useContext 可跨级获取信息
//1.在需要的父级定义上下文,并提供数据
import { createContext } from "react";
export const MsgContext = createContext(null);
const msgData ={
name: "DGDHUJ"
}
<MsgContext.Provider value={ msgData }>
<App />
</MsgContext .Provider>
//子组件中获取信息
const childMsgContext = useContext(MsgContext)
结合useState使子组件可以更改父组件信息
//1.在需要的父级定义上下文,并提供数据
import { createContext } from "react";
export const MsgContext = createContext(null);
const msgData ={
name: "DGDHUJ"
}
const [toChildMsgData, settoChildMsgData] = useState(msgData )
<MsgContext.Provider value={ settoChildMsgData }>
<App />
</MsgContext .Provider>
//子组件中获取信息
const childMsgContext = useContext(MsgContext)
const changeFn = ()=>{
childMsgContext({
name: "new_DGDHUJ"
})
}
2.引用钩子useRef 获取dom
1.使用useRef获取DOM元素
import { useRef, MutableRefObject } from 'react';
const Demo = () => {
let inputEle: MutableRefObject<any> = useRef(null);
const getDom = ()=>{
console.log(inputEle)
}
return (
<>
<input ref={ inputEle } type="text" />
<button onClick={getDom}></button>
</>
)
};
export default Demo;
2.使用useRef获取子组件中的DOM元素
import { forwardRef, useEffect, useRef } from "react";
const Demo = () => {
let childRef = useRef(null);
const getDom = ()=>{
console.log(childRef )
}
return (
<>
<Child ref={ childRef } />
<button onClick={getDom}></button>
</>
);
};
//forwardRef将父类的ref作为参数传给子组件
const Child = forwardRef((props, ref) => {
return (
<>
<input type="text" ref={ ref } />
</>
);
})
export default Demo;
3.使用useRef获取子组件中的属性和方法
import {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
const Demo = () => {
let childRef = useRef(null);
const getDom = ()=>{
console.log(childRef )
childRef.current.sayHello()
}
return (
<>
<Child ref={childRef} />
<button onClick={getDom}></button>
</>
);
};
//useImperativeHandle 将子组件中的方法和state暴露到ref中,父组件可以通过ref获取到
const Child = forwardRef((props, ref: any) => {
const [count, setCount] = useState(0);
const sayHello = () => {
console.log("你好!");
};
useImperativeHandle(ref, () => {
return {
count,
sayHello,
};
});
return (
<>
</>
);
});
export default Demo;
4.副作用钩子useEffect
副作用让组件 连接到外部系统并与之同步。这包括处理网络、浏览器 DOM、动画、使用不同的 UI 库编写的小部件,以及其他非 React 代码
import { useEffect } from 'react';
const Demo = () => {
//[]为依赖项,空为只执行一次,有值则初次渲染和依赖值改变都会执行
useEffect(()=>{
console.log("执行了")
},[])
return (
<>
<div>aaa</div>
</>
)
};
export default Demo;
消除副作用
useEffect(() => {
const id = setInterval(() => {
setCount(count => count+1)
}, 1000)
return () => clearInterval(id)
}, [])
5.资源钩子use
组件可以访问资源,而无需将它们作为其状态的一部分。例如,组件可以从 Promise 读取消息或从上下文读取样式信息。
import { fetchMessage } from './lib.js';
import { Message } from './message.js';
export default function App() {
const messagePromise = fetchMessage();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
// message.js
'use client';
import { use } from 'react';
export function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <p>Here is the message: {messageContent}</p>;
}
6.资源钩子useCallback
在重新渲染之间缓存函数定义
function ProductPage({ productId, referrer, theme }) {
// Tell React to cache your function between re-renders...
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]); // ...so as long as these dependencies don't change...
return (
<div className={theme}>
{/* ...ShippingForm will receive the same props and can skip re-rendering */}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
7.useDebugValue
可让你将标签添加到 React 开发工具 中的自定义钩子。
import { useDebugValue } from 'react';
function useOnlineStatus() {
// ...
useDebugValue(isOnline ? 'Online' : 'Offline');
// ...
}
8.useDeferredValue
可让你推迟更新 UI 的一部分。
import { useState, useDeferredValue } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
// ...
}
8.useId
于生成可传递给可访问性属性的唯一 ID
import { useId } from 'react';
function PasswordField() {
const passwordHintId = useId();
return (
<>
<label>
Password:
<input
type="password"
aria-describedby={passwordHintId}
/>
</label>
<p id={passwordHintId}>
The password should contain at least 18 characters
</p>
</>
);
}
9.useImperativeHandle
可让你自定义公开为 引用 的句柄。
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
10.useInsertionEffect
允许在任何布局效果触发之前将元素插入 DOM。
// Inside your CSS-in-JS library
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// As explained earlier, we don't recommend runtime injection of <style> tags.
// But if you have to do it, then it's important to do in useInsertionEffect.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
11.useLayoutEffect
在浏览器重绘屏幕之前触发
useLayoutEffect(setup, dependencies?)
12.useMemo
可让你在重新渲染之间缓存计算结果。
import { useMemo } from 'react';
import { filterTodos } from './utils.js'
export default function TodoList({ todos, theme, tab }) {
const visibleTodos = useMemo(
() => filterTodos(todos, tab),
[todos, tab]
);
return (
<div className={theme}>
<p><b>Note: <code>filterTodos</code> is artificially slowed down!</b></p>
<ul>
{visibleTodos.map(todo => (
<li key={todo.id}>
{todo.completed ?
<s>{todo.text}</s> :
todo.text
}
</li>
))}
</ul>
</div>
);
}
13.useReducer
可让你将 reducer 添加到组件中。
import { useReducer } from 'react';
function reducer(state, action) {
if (action.type === 'incremented_age') {
return {
age: state.age + 1
};
}
throw Error('Unknown action.');
}
export default function Counter() {
const [state, dispatch] = useReducer(reducer, { age: 42 });
return (
<>
<button onClick={() => {
dispatch({ type: 'incremented_age' })
}}>
Increment age
</button>
<p>Hello! You are {state.age}.</p>
</>
);
}
14.useSyncExternalStore
可让你订阅外部存储。
import { useSyncExternalStore } from 'react';
import { todosStore } from './todoStore.js';
export default function TodosApp() {
const todos = useSyncExternalStore(todosStore.subscribe, todosStore.getSnapshot);
return (
<>
<button onClick={() => todosStore.addTodo()}>Add todo</button>
<hr />
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
</>
);
}
在let nextId = 0;
let todos = [{ id: nextId++, text: 'Todo #1' }];
let listeners = [];
export const todosStore = {
addTodo() {
todos = [...todos, { id: nextId++, text: 'Todo #' + nextId }]
emitChange();
},
subscribe(listener) {
listeners = [...listeners, listener];
return () => {
listeners = listeners.filter(l => l !== listener);
};
},
getSnapshot() {
return todos;
}
};
function emitChange() {
for (let listener of listeners) {
listener();
}
}
14.useTransition
可让你在不阻塞 UI 的情况下更新状态。
import { useState, useTransition } from 'react';
import TabButton from './TabButton.js';
import AboutTab from './AboutTab.js';
import PostsTab from './PostsTab.js';
import ContactTab from './ContactTab.js';
export default function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
return (
<>
<TabButton
isActive={tab === 'about'}
onClick={() => selectTab('about')}
>
About
</TabButton>
<TabButton
isActive={tab === 'posts'}
onClick={() => selectTab('posts')}
>
Posts (slow)
</TabButton>
<TabButton
isActive={tab === 'contact'}
onClick={() => selectTab('contact')}
>
Contact
</TabButton>
<hr />
{tab === 'about' && <AboutTab />}
{tab === 'posts' && <PostsTab />}
{tab === 'contact' && <ContactTab />}
</>
);
}
二、组件
1. Fragment
允许你在没有封装器节点的情况下对元素进行分组。
function Post() {
return (
<>
<PostTitle />
<PostBody />
</>
);
}
2.Profiler
允许你以编程方式测量 React 树的渲染性能。
<App>
<Profiler id="Sidebar" onRender={onRender}>
<Sidebar />
</Profiler>
<PageContent />
</App>
3.StrictMode
为整个应用启用严格模式
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<App />
</StrictMode>
);
4.Suspense
允许你显示回退,直到其子级完成加载。
import { Suspense } from 'react';
import Albums from './Albums.js';
export default function ArtistPage({ artist }) {
return (
<>
<h1>{artist.name}</h1>
<Suspense fallback={<Loading />}>
<Albums artistId={artist.id} />
</Suspense>
</>
);
}
function Loading() {
return <h2> Loading...</h2>;
}
三、API
1.cache
允许你缓存数据获取或计算的结果。
import {cache} from 'react';
import calculateUserMetrics from 'lib/user';
const getUserMetrics = cache(calculateUserMetrics);
function Profile({user}) {
const metrics = getUserMetrics(user);
// ...
}
function TeamReport({users}) {
for (let user in users) {
const metrics = getUserMetrics(user);
// ...
}
// ...
}
2.createContext
允许你创建组件可以提供或读取的 上下文。
import { createContext } from 'react';
const ThemeContext = createContext('light');
3.forwardRef
允许你的组件使用 引用 向父组件公开 DOM 节点
const MyInput = forwardRef(function MyInput(props, ref) {
return (
<label>
{props.label}
<input ref={ref} />
</label>
);
});
4.lazy
允许你推迟加载组件的代码,直到它第一次渲染。
import { lazy } from 'react';
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
5.memo
允许你在属性不变时跳过重新渲染组件。
const Greeting = memo(function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
});
export default Greeting;
6.startTransition
允许你在不阻塞 UI 的情况下更新状态。
import { startTransition } from 'react';
function TabContainer() {
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
// ...
}