参考链接:
React 内置 Hook
Hook简单介绍
定义: 以use开头的函数
作用: Hook有助于在组件中使用不同的React功能
使用: Hook比普通函数更为严格,只能在的组件(或其他 Hook)的 顶层 调用Hook
分类:
- State Hook
- Context Hook
- Ref Hook
- Effect Hook
- 性能 Hook
- 其他 Hook
- 自定义 Hook
State Hook
状态帮助组件,用于“记住”用户的输入信息
useState :声明可以直接更新的状态变量
示例:
function MyButton(){
const [count,setCount] = useState(0);
function handleClick(){
setCount(count+1);
}
return(
<button onClick={handleClick}>
Clicked {count} times
</button>
)
}useReducer:在reducer函数中声明带有更新逻辑的state变量
reducer函数 :将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫做reducer
useReducer钩子
接受参数:
- 一个reducer函数
- 一个初始的state
返回内容:
- 一个有状态的值
- 一个dispatch函数(派发用户操作给reducer)
示例:
import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
import tasksReducer from './tasksReducer.js';
export default funtion TaskApp(){
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
function handleAddTask(text){
dispatch({
type:'added',
id:nextId++,
text:text,
});
}
function handleChangeTask(task){
dispatch({
type:'changed',
task:task
});
}
function handleDeleteTask(taskId){
dispatch({
type:'deleted',
id:taskId,
});
}
return (
<>
<h1>布拉格的行程安排</h1>
<AddTask onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</>
);
}{/tabs-pane}
{tabs-pane label="tasksReducer.js"}
export default function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [
...tasks,
{
id: action.id,
text: action.text,
done: false,
},
];
}
case 'changed': {
return tasks.map((t) => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter((t) => t.id !== action.id);
}
default: {
throw Error('未知 action:' + action.type);
}
}
}
{/tabs-pane}
Context Hook
上下文帮助组件 从祖先组件接收信息,而无需将其作为 props 传递
useContext 读取订阅上下文
示例:
import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);
export default function MyApp(){
return (
<ThemeContext.Provider value="dark">
<Form/>
<ThemeContext.Provider>
);
}
function Form(){
return (
<Panel title="Welcome">
<Button>Sign up </Button>
<Button>Log in </Button>
</Panel>
);
}
function Panel({title,children}){
const theme = useContext(ThemeContext);
const className = 'panel-' + theme;
return(
<section className = {className}}>
<h1>{title}</h1>
{children}
</section>
);
}
funciton Button({children}){
const theme = useContext(ThemeContext);
const className = 'button-' + theme;
return(
<button className={className}>
{children}
</button>
);
}注意:通常情况下,useContext()只会调用上层provider,当然通过合并的方式可以实现嵌套调用
Ref Hook
ref 允许组件 保存一些不用于渲染的信息,比如 DOM 节点或 timeout ID。与状态不同,更新 ref 不会重新渲染组件。
useRef 声明ref,可以保存任何值,但常用于保存DOM节点
示例:
import { useRef } from 'react';
export default function Counter() {
let ref = useRef(0);
function handleClick() {
ref.current = ref.current + 1;
alert('You clicked ' + ref.current + ' times!');
}
return (
<button onClick={handleClick}>
点击!{ref.current}
</button>
);
}
与useState不同的是,ref不会触发重新渲染,所以JSX中显示{ref.current}不会变化
useImperativeHandle 自定义从组件中暴露ref,不常用
Effect Hook
Effect 允许组件 连接到外部系统并与之同步。这包括处理网络、浏览器、DOM、动画、使用不同 UI 库编写的小部件以及其他非 React 代码
useEffect 将组件连接到外部系统
外部系统 :有些组件需要与网络、某些浏览器 API 或第三方库保持连接,当它们显示在页面上时。这些系统不受 React 控制,所以称为外部系统
示例:
import {useState,useEffect} from 'react';
import {createConnection} from './chat.js';
function ChatRoom({roomId}){
const [serverUrl,setServerUrl] = useState('https://localhost:1234');
useEffect(()=>{
const connection = createConnection(serverUrl,roomId);
connection.connect();
return ()=>{
connection.disconnection();
};
},[serverUrl,roomId]);
// ...
}需要向 useEffect 传递两个参数:
- 一个 setup 函数 ,其 setup 代码 用来连接到该系统。
它应该返回一个 清理函数(cleanup),其 cleanup 代码 用来与该系统断开连接。
- 一个 依赖项列表,包括这些函数使用的每个组件内的值
性能 Hook
使用性能hook可以跳过计算和不必要的重新渲染来优化性能
useMemo 缓存计算代价昂贵的计算结果
useMemo(calculateValue, dependencies)
calculateValue:要缓存计算值的函数
dependencies:所有在 calculateValue 函数中使用的响应式变量组成的数组示例:
import { useState } from 'react';
import { createTodos } from './utils.js';
import TodoList from './TodoList.js';
const todos = createTodos();
export default funtion App(){
const [tab,setTab] = useState('all');
const [isDark,setIsDark] = useState(false);
return(
<>
<button onClick={()=>setTab('all')}>All</button>
<button onClick={()=>setTab('active')}>Active</button>
<button onClick={()=>setTab('completed')}>Completed</button>
<br/>
<label>
<input type="checkbox" checked={isDark} onChange={e=>setIsDark(e.target.checked)}>
Dark mode
</input>
</label>
<hr/>
<TodoList todos={todos} tab={tab} theme={isDark?'dark':'light'}/>
</>
);
}
{/tabs-pane}
{tabs-pane label="TodoList.js"}
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>
);
}
{/tabs-pane}
{tabs-pane label="utils.js"}
export function createTodos() {
const todos = [];
for (let i = 0; i < 50; i++) {
todos.push({
id: i,
text: "Todo " + (i + 1),
completed: Math.random() > 0.5
});
}
return todos;
}
export function filterTodos(todos, tab) {
console.log('[ARTIFICIALLY SLOW] Filtering ' + todos.length + ' todos for "' + tab + '" tab.');
let startTime = performance.now();
while (performance.now() - startTime < 500) {
// 在 500 毫秒内不执行任何操作以模拟极慢的代码
}
return todos.filter(todo => {
if (tab === 'all') {
return true;
} else if (tab === 'active') {
return !todo.completed;
} else if (tab === 'completed') {
return todo.completed;
}
});
}
{/tabs-pane}
useCallback 将函数传递给优化组件之前缓存函数定义
const cachedFn = useCallback(fn, dependencies)
fn:想要缓存的函数
dependencies:有关是否更新 fn 的所有响应式值的一个列表示例:
function ProductPage({ productId, referrer, theme }) {
// 在多次渲染中缓存函数
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]); // 只要这些依赖没有改变
return (
<div className={theme}>
{/* ShippingForm 就会收到同样的 props 并且跳过重新渲染 */}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}useMemo与useCallback联系
useMemo 经常与 useCallback 一同出现,区别在于
useMemo 缓存函数调用的结果
useCallback 缓存函数本身
// 在 React 内部的简化实现
function useCallback(fn, dependencies) {
return useMemo(() => fn, dependencies);
}示例:
import { useMemo, useCallback } from 'react';
function ProductPage({ productId, referrer }) {
const product = useData('/product/' + productId);
const requirements = useMemo(() => { //调用函数并缓存结果
return computeRequirements(product);
}, [product]);
const handleSubmit = useCallback((orderDetails) => { // 缓存函数本身
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
return (
<div className={theme}>
<ShippingForm requirements={requirements} onSubmit={handleSubmit} />
</div>
);
}其他 Hook
- 使用 useDebugValue 自定义 React 开发者工具为自定义 Hook 添加的标签。
- 使用 useId 将唯一的 ID 与组件相关联,其通常与可访问性 API 一起使用。
- 使用 useSyncExternalStore 订阅外部 store。
- 使用 useActionState 允许你管理动作的状态.
评论 (0)