useCallback(fn, dependencies)
useCallback 是一个允许你在多次渲染中缓存函数的 React Hook。
TIP
当传递一个函数给子组件的时候,父组件如果刷新了,此时函数会重新变化内存地址,导致子组件(已经使用 memo 进行缓存)也会刷新,因此需配合 useCallback 将传递的函数进行缓存,子组件才不会刷新
// 在 React 内部的简化实现
function useCallback(fn, dependencies) {
return useMemo(() => fn, dependencies)
}useContext(SomeContext)
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>
)
}
function Button({ children }) {
const theme = useContext(ThemeContext)
const className = `button-${theme}`
return <button className={className}>{children}</button>
}useEffect(setup, dependencies?)
useEffect 是一个 React Hook,它允许你 将组件与外部系统同步。( 可以用于接口请求,避免组件重新渲染导致的重新请求,返回值用于清除副作用)
import { 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.disconnect()
}
}, [serverUrl, roomId])
// ...
}useId()
可以生成传递给无障碍属性的唯一 ID。
// 举例来说,假设你不想暴露出整个 <input> DOM 节点,但你想要它其中两个方法:focus 和 scrollIntoView。为此,用单独额外的 ref 来指向真实的浏览器 DOM。然后使用 useImperativeHandle 来暴露一个句柄,它只返回你想要父组件去调用的方法:
import { forwardRef, useImperativeHandle, useRef } from 'react'
const MyInput = forwardRef((props, ref) => {
const inputRef = useRef(null)
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus()
},
scrollIntoView() {
inputRef.current.scrollIntoView()
},
}
}, [])
return (
<input
{...props}
ref={inputRef}
/>
)
})forwardRef(render)
允许组件使用 ref 将 DOM 节点暴露给父组件。(就是将子组件的 dom 暴露出来,父组件可以使用 useRef 来进行关联,从而操作子组件的 dom)
// 子组件
import { forwardRef } from 'react'
const MyInput = forwardRef((props, ref) => {
const { label, ...otherProps } = props
return (
<label>
{label}
<input
{...otherProps}
ref={ref}
/>
</label>
)
})
// 父组件
function Form() {
const ref = useRef(null)
function handleClick() {
ref.current.focus()
}
return (
<form>
<MyInput
label="Enter your name:"
ref={ref}
/>
<button
type="button"
onClick={handleClick}
>
编辑
</button>
</form>
)
}memo(Component, arePropsEqual?)
允许你的组件在 props 没有改变的情况下跳过重新渲染
import { memo } from 'react'
const Greeting = memo(({ name }) => {
return (
<h1>
Hello,
{name}!
</h1>
)
})useLayoutEffect(setup, dependencies?)
useLayoutEffect 是 useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。
// 调用 useLayoutEffect 在浏览器重新绘制屏幕之前进行布局测量:
import { useLayoutEffect, useRef, useState } from 'react'
function Tooltip() {
const ref = useRef(null)
const [tooltipHeight, setTooltipHeight] = useState(0)
useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect()
setTooltipHeight(height)
}, [])
}useReducer(reducer, initialArg, init?)
跟 useState 比较类似,只不过是先把 action 都定义好了,之后值的修改就通过 dispatch 进行操作
import { useReducer } from 'react'
function reducer(state, action) {
if (action.type === 'incremented_age') {
return {
age: state.age + 1,
}
}
throw new 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>
</>
)
}useRef(initialValue)
它能帮助引用一个不需要渲染的值(useRef会返回一个对象,这个对象上有 current 这个属性,对这个属性的值进行修改,不会导致组件的重新渲染;如果是对 dom 使用,则 current 会变成对这个 dom 的引用)
import { useRef } from 'react'
export default function Form() {
const inputRef = useRef(null)
function handleClick() {
inputRef.current.focus()
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>聚焦输入框</button>
</>
)
}
// or...
const intervalRef = useRef(0)
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000)
intervalRef.current = intervalId
}useState(initialState)
import { useState } from 'react'
function MyComponent() {
const [age, setAge] = useState(28)
const [name, setName] = useState('Taylor')
const [todos, setTodos] = useState(() => createTodos())
// ...
}DANGER
useState 是一个 Hook,因此你只能在 组件的顶层 或自己的 Hook 中调用它。你不能在循环或条件语句中调用它。如果你需要这样做,请提取一个新组件并将状态移入其中。
startTransition
用于将状态更新标记为低优先级(过渡更新),从而避免阻塞高优先级的用户交互(如输入、点击等),提升应用的响应性和用户体验。
import { startTransition } from 'react'
// 紧急更新:输入框即时响应
setInputValue(input)
// 过渡更新:延迟处理筛选逻辑
startTransition(() => {
setSearchResults(filterData(input))
})
// Hook 版
const [isPending, startTransition] = useTransition()性能相关优化
https://juejin.cn/post/7491567546770276361
useActionState
根据表单动作的结果更新 state 的 Hook。
import { useActionState } from 'react'
async function increment(previousState, formData) {
// 返回的数据可以通过 state 拿到,也可以是对象({state: 'success', message: 'ok'})等类型
return previousState + 1
}
function StatefulForm({}) {
const [state, formAction] = useActionState(increment, 0)
return (
<form action={formAction}>
{state}
<button type="submit">+1</button>
</form>
)
}