You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Instead, use useEffect. The function passed to useEffect will run after the render is committed to the screen. Think of effects as an escape hatch from React's purely functional world into the imperative world.
Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID. To do this, the function passed to useEffect may return a clean-up function. For example, to create a subscription:
functionTextInputWithFocusButton(){constinputEl=useRef(null);constonButtonClick=()=>{// `current` points to the mounted text input elementinputEl.current.focus();};return(<><inputref={inputEl}type="text"/><buttononClick={onButtonClick}>Focus the input</button></>);}
functionuseFriendStatus(friendID){const[isOnline,setIsOnline]=useState(null);// ...// Show a label in DevTools next to this Hook// e.g. "FriendStatus: Online"useDebugValue(isOnline ? 'Online' : 'Offline');returnisOnline;}
本文博客地址:React Hooks 文档翻译 - 7 - Hooks API Reference(Hooks API 参考).
翻译自:https://reactjs.org/docs/hooks-reference.html
Hooks 是 React 16.8 新增的功能。它允许你在不编写类的情况下使用状态和其他 React 特性。
If you're new to Hooks, you might want to check out the overview first. You may also find useful information in the frequently asked questions section.
如果你是 Hooks 的新手,可能需要先查看概述。你还可以在常见问题部分找到有用的信息。
Basic Hooks
useState
返回一个状态值,以及一个更新它的函数。
在首次渲染时,返回的状态(
state
)与传递给它的第一个参数(initialState
)的值相同。setState
函数用于更新状态。它接受一个新的状态值,并将组件的重新渲染排入队列。在后续的重新渲染中,
useState
返回的第一个值将始终是更新后的最新状态。Functional updates
如果新状态需要使用先前的状态来计算,则可以传递函数给
setState
。该函数接收先前的状态值做为参数,并返回更新后的值。下面示例演示了使用两种形式的setState
的计数器组件:“+” 和 “-” 按钮使用函数形式,因为更新后的值基于先前的值。“重置”按钮则使用普通的形式,因为它总是将计数设置回 0。
Lazy initialization
initialState
参数是首次渲染时使用的状态。在随后的渲染中,它将被忽略。如果初始状态是一个复杂计算的结果,则可以改为提供函数参数,且该函数仅在首次渲染时执行:useEffect
接受一个函数参数,包含命令式,有副作用的代码。
如突变,订阅,计时器,日志记录和其他副作用等都不允许在函数组件的主体内使用(也即不允许在 React 的渲染阶段运行)。这会导致 UI 中出现错误和不一致的混乱。
Instead, use
useEffect
. The function passed touseEffect
will run after the render is committed to the screen. Think of effects as an escape hatch from React's purely functional world into the imperative world.相反,使用
useEffect
。传递给useEffect
的函数将在渲染更新到屏幕后运行。将 effects 视为从 React 的纯粹功能性世界进入命令式世界的“逃生舱”。默认情况下,effects 在每次完成渲染后运行,但你可以选择仅在某些值发生更改时触发它。
Cleaning up an effect
Often, effects create resources that need to be cleaned up before the component leaves the screen, such as a subscription or timer ID. To do this, the function passed to
useEffect
may return a clean-up function. For example, to create a subscription:通常, effect 创建的资源在组件从屏幕上消失前需要被清理,例如订阅数据源或定时器的 ID。为了清理,传递给
useEffect
的函数可以返回一个清理函数。例如,创建订阅的返回:清除函数在从 UI 中删除组件前运行,以防止内存泄漏。此外,如果组件渲染多次(通常都是这样),则在**执行下一个 effect 前会清除先前的 effect **。在我们的示例中,意味着每次更新都会创建一个新订阅。要避免每次更新都触发 effect ,请参阅下一节。
Timing of effects
与
componentDidMount
和componentDidUpdate
不同,传递给useEffect
的函数在布局和绘制到屏幕之后触发。这使得它适用于许多常见的副作用,例如设置订阅和事件处理,因为大多数此类型的工作不应该阻止浏览器更新屏幕的内容。但是,并非所有 effect 都可以推迟。例如,对用户可见的 DOM 突变必须在下一次绘制之前同步触发,以便用户不会感觉到视觉上的不一致。(它们区别在概念上类似于被动事件侦听器和活动事件侦听器。)对于这些类型的 effects ,React 提供了一个名为
useLayoutEffect
的附加 Hook。它与useEffect
具有相同的签名,仅仅在触发时机不同。虽然
useEffect
延迟到浏览器绘制完成之后,但 React 保证它在任何新渲染发生前会被触发。在开始新的更新之前,React 将始终刷新先前渲染的 effect 。Conditionally firing an effect
有条件地触发 effect
effect 的默认行为是在每次完成渲染后触发 effect 。这种情况下,如果任何一个传入的参数发生变化,则始终会重新创建 effect 。
但是,在某些情况下,可能是矫枉过正的,例如上一节中的订阅示例。我们无需在每次组件更新时创建新的订阅,除非
source
这个 props 发生了变化。要实现这样的功能,请传递给
useEffect
第二个参数,它是 effect 所依赖的值数组。更改后的示例是这样的:现在只有在
props.source
发生更改时才会重新创建订阅。依赖的数组并不会作为参数传递给 effect 函数。但从概念上讲,它们就是这样表达的:effect 函数内引用的每个值应该出现在所依赖的数组中。将来,一个足够先进的编译器可以自动创建这个数组。
useContext
接受 Context 对象(从
React.createContext
返回的值)并返回当前的 Context 值的函数,当前 Context 值由组件树上方最近的<MyContext.Provider>
确定。当组件最近的
<MyContext.Provider>
更新时,此 Hook 将触发重新渲染,并将最新的 Context 值传递给该MyContext
provider。不要忘记
useContext
的参数必须是 Context 对象本身:useContext(MyContext)
useContext(MyContext.Consumer)
useContext(MyContext.Provider)
当 Context 值更改时,调用
useContext
的组件始终将重新渲染。如果重新渲染组件的代价很昂贵,可以使用 memoization 优化。Additional Hooks
以下 Hooks 可能是上一节中基本的 Hooks 的变体,也可能仅用于特定的边缘情况。现在不用急着学习它们。
useReducer
useState
的替代方案。接受类型为(state, action) => newState
的 reducer,并返回与当前状态配对的dispatch
方法。(如果你熟悉 Redux,你肯定了解它是如何工作的。)当你有多个涉及子值的复杂状态逻辑或下一个状态取决于前一个状态时,
useReducer
通常优于useState
。useReducer
还允许你优化触发深度更新的组件的性能,因为你可以传递dispatch
而不是使用回调。这是
useState
一节的计数器示例,使用 reducer 重写为:Specifying the initial state
指定初始状态
有两种不同的方法初始化
useReducer
状态。你可以根据用例选择其中一个。最简单方法是将初始状态作为第二个参数传递给useReducer
:Lazy initialization
懒初始化
你还可以推迟创建初始状态。为此,可以将
init
函数作为第三个参数传递。初始状态将设置为init(initialArg)
。它允许你提取计算初始状态的逻辑到 reducer 的外部。这对于稍后重置状态以响应操作也很方便:
Bailing out of a dispatch
如果从 Reducer Hook 返回与当前状态相同的值,则 React 将不渲染子组件且不触发 effects。(React 使用
Object.is
比较算法 。)注意,React 可能仍需要在停止渲染子组件前再次渲染该组件。这不应该不是问题,因为 React 不会不必要地“深入”到子组件树中。如果你在渲染时进行了昂贵的计算,则可以使用
useMemo
对其进行优化。useCallback
返回一个 memoized 的回调。
传递内联回调函数和数组依赖。
useCallback
将返回一个回调函数的 memoized 版本,它只有在其中一个依赖项发生更改时才会更改。这非常有用,通过将回调传递给依赖引用相等性判断优化过的子组件,可以防止不必要的渲染(例如,shouldComponentUpdate
)。useCallback(fn, deps)
等同于useMemo(() => fn, deps)
.useMemo
返回一个 memoized 的值。
传递一个执行“创建”的函数和依赖的变量的数组。
useMemo
只会在其中一个依赖的变量发生更改时重新计算 memoized的值。此优化有助于避免在每个渲染时进行昂贵的计算。请记住,传递给
useMemo
的函数在渲染中运行。不要做那些在渲染时通常不会做的事情。例如,副作用通常属于useEffect
,而不是useMemo
。如果未提供数组,则将在每次渲染是都会重新计算值。
**你可以依赖
useMemo
作为性能优化,而不是语义保证。**将来,React 可能会选择“忘记”一些以前记忆的值,并在下一次渲染时重新计算它们,例如为屏幕外组件释放内存。写代码时,确保在没有useMemo
的情况下仍可正常工作 -- 然后再考虑添加它优化性能。useRef
useRef
返回一个可变的 ref 对象,其.current
属性被初始化为传递的参数(initialValue
)。返回的对象将持续整个组件的生命周期。一个常见的用例是强行访问子组件对象:
本质上,
useRef
就像一个“盒子”,可以在其.current
属性中保存一个可变值。你可能了解 refs 主要是作为 访问 DOM 的一种方式。如果使用
<div ref={myRef} />
将 ref 对象传递给 React,只要该节点发生更改,React 就会将其.current
属性设置为相应的DOM 节点。但是,
useRef()
比 ref 属性更有用。使用它随手保存任何可变值 与你在类中使用实例字段的方式类似,这很方便。这样可以工作,因为
useRef()
创建了一个普通的 JavaScript 对象。useRef()
与自己创建{current: ...}
对象之间的唯一区别是useRef
会在每次渲染时为你提供同一个 ref 对象。请记住,
useRef
在内容更改时不会通知你。.current
属性的改变不会导致重新渲染。如果要在 React 将引用附加到 DOM 节点或从 DOM 节点分离时运行某些代码,可使用callback ref替代。useImperativeHandle
useImperativeHandle
自定义使用ref
时公开给父组件的实例值。与以前一样,在大多数情况下应避免使用 refs 的命令式代码。useImperativeHandle
应与forwardRef
一起使用:在这个例子里,渲染了
<FancyInput ref={fancyInputRef} />
的父组件能够调用fancyInputRef.current.focus()
。useLayoutEffect
签名与
useEffect
相同,但在所有 DOM 突变后会同步触发。使用它从 DOM 读取布局并同步重新渲染,在useLayoutEffect
内部计划的更新将在浏览器有机会重绘前同步刷新到屏幕。如果可能的话,首选标准的
useEffect
以避免阻塞视觉更新。useDebugValue
useDebugValue
可用于在 React DevTools 中显示自定义挂钩的标签。例如,在“构建自己的Hooks”中描述的
useFriendStatus
的自定义 Hook:Defer formatting debug values
推迟格式化调试值
在某些情况下,格式化显示值可能是昂贵的操作。除非检查 Hook,否则没有必要。
因此,
useDebugValue
接受格式化函数作为可选的第二个参数。只有在检查 Hooks 时才会调用此功能。它接收调试值作为参数,并应返回格式化后的显示值。例如,返回
Date
值的自定义 Hook 可以通过传入以下格式化程序来避免不必要地调用toDateString
函数:The text was updated successfully, but these errors were encountered: