做网站第二年要续费吗,刷单网站搭建,网站群建设系统,网站转html5useCallback(fn, dependencies)
useCallback是一个React Hook#xff0c;它允许您在重新渲染之间缓存函数定义。
const cachedFn useCallback(fn, dependencies)1、参数#xff1a;
fn#xff1a;要缓存的函数值。它可以接受任何参数并返回任何值。React将在初始渲染期间…useCallback(fn, dependencies)
useCallback是一个React Hook它允许您在重新渲染之间缓存函数定义。
const cachedFn useCallback(fn, dependencies)1、参数
fn要缓存的函数值。它可以接受任何参数并返回任何值。React将在初始渲染期间返回而不是调用您的函数。在下一次渲染中如果自上次渲染以来依赖项没有更改React将再次为您提供相同的函数。否则它将为您提供在当前渲染过程中传递的函数并将其存储起来以备以后重用。React不会调用您的函数。函数将返回给您以便您可以决定何时以及是否调用它。
dependencies:fn代码内部引用的所有反应值的列表。反应值包括props、state以及直接在组件体内声明的所有变量和函数。如果您的linter配置为React它将验证每个React值是否正确指定为依赖项。依赖项列表必须具有恒定数量的项并且像[dep1dep2dep3]一样以内联方式编写。React将使用Object.is的比较算法将每个依赖项与其以前的值进行比较。
2、返回值
在初始渲染时useCallback返回您传递的fn函数。 在随后的渲染过程中它将从上次渲染中返回一个已经存储的fn函数如果依赖项没有更改或者返回您在此渲染过程中传递的fn函数。
3、告诫
useCallback是一个Hook所以您只能在组件的顶层或您自己的Hook中调用它。不能在循环或条件内部调用它。如果需要请提取一个新组件并将状态移动到其中。
4、用法
在以下渲染中React将把依赖项与您在上一次渲染中传递的依赖项进行比较。如果任何依赖项都没有更改与Object.is相比useCallback将返回与以前相同的函数。否则useCallback将返回在此渲染中传递的函数。
import { useCallback } from react;export default function ProductPage({ productId, referrer, theme }) {const handleSubmit useCallback((orderDetails) {post(/product/ productId /buy, {referrer,orderDetails,});}, [productId, referrer]);默认情况下当组件重新渲染时React会递归地重新渲染其所有子级。这就是为什么当ProductPage使用不同的主题重新渲染时ShippingForm组件也会重新渲染。这对于不需要太多计算即可重新渲染的组件来说很好。但是如果验证了重新渲染的速度较慢则可以通过将其包装在备忘录中告诉ShippingForm在其道具与上次渲染相同时跳过重新渲染
function ProductPage({ productId, referrer, theme }) {// ...return (div className{theme}ShippingForm onSubmit{handleSubmit} //div);使用了memo包裹子组件只有prop变化时才会重新渲染否则就跳过重新渲染
import { memo } from react;const ShippingForm memo(function ShippingForm({ onSubmit }) {// ...
});在JavaScript中函数{}或{}总是创建不同的函数类似于{}对象文字总是创建新对象的方式。通常情况下这不会是一个问题但这意味着ShippingForm道具将永远不会相同您的备忘录优化也不会起作用。在这个例子中父组件的prop变化时函数会重新创建即使子组件使用memeo依然不起作用因为handleSubmit每次都不同
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 dont change...return (div className{theme}{/* ...ShippingForm will receive the same props and can skip re-rendering */}ShippingForm onSubmit{handleSubmit} //div);
}现在我们就可以将他等着在useCallback只有依赖项变化时才会返回新的函数定义。一般情况下我们不必将函数使放在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 dont change...return (div className{theme}{/* ...ShippingForm will receive the same props and can skip re-rendering */}ShippingForm onSubmit{handleSubmit} //div);
}5、useCallack和useMemo 的区别
useMemo缓存调用函数的结果。useCallback缓存函数本身。 const requirements useMemo(() { // Calls your function and caches its resultreturn computeRequirements(product);}, [product]);const handleSubmit useCallback((orderDetails) { // Caches your function itselfpost(/product/ productId /buy, {referrer,orderDetails,});}, [productId, referrer]);可以想象成这样
// Simplified implementation (inside React)
function useCallback(fn, dependencies) {return useMemo(() fn, dependencies);
}6、何时使用useCallack
如果你的应用程序像这个网站并且大多数交互都很粗糙比如替换一个页面或整个部分那么通常不需要记忆。另一方面如果你的应用程序更像一个绘图编辑器并且大多数交互都是细粒度的比如移动的形状那么你可能会发现记忆非常有用。 使用useCallback缓存函数只有在少数情况下才有价值 1、您将函数作为餐厨传递给了memo包裹的子组件 2、您传递的函数稍后将用作某个Hook的依赖项。例如包装在useCallback中的另一个函数依赖于它或者您依赖于useEffect中的此函数。 在其他情况下用useCallback包装函数没有任何好处。这样做也没有重大危害所以一些团队选择不考虑个别案例并尽可能多地记忆。缺点是代码的可读性变差。此外并非所有的记忆都是有效的一个“总是新的”值就足以破坏整个组件的记忆。
useContext(SomeContext)
useContext是一个React Hook它允许您从组件中读取和订阅上下文。
import { useContext } from react;function MyComponent() {const theme useContext(ThemeContext);// ...1、参数
SomeContext您之前使用createContext创建的上下文。
2、返回值
useContext返回调用组件的上下文值返回的值始终是最新的
3、告诫
相应的Context.Provider需要位于执行useContext调用的组件之上。
4、用法
深层数据传递、通过context传递更新数据 react 会找桑钱上下文最近的provider不论层级多深都可以使用useContext(ThemeContext),访问到
function MyPage() {return (ThemeContext.Provider valuedarkForm //ThemeContext.Provider);
}function Form() {// ... renders buttons inside ...
}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]);// ...
}1、参数
setup具有Effect逻辑的函数。您的设置函数也可以选择返回一个清理函数。 可选依赖项设置代码内部引用的所有反应值的列表。反应值包括props、state以及直接在组件体内声明的所有变量和函数。
2、用法
连接到外部系统某些组件在页面上显示时需要保持与网络、某些浏览器API或第三方库的连接。这些系统不受React控制所以它们被称为外部系统。 例如 一个由setInterval和clearInterval.管理的计时器。 使用window.addEventListener和window.removeEventLister的事件订阅。 带有API的第三方动画库如animation.start和animation.reset
3、解释
感觉官网的解释有些晦涩一般我们是这么理解的 可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdate 和 componentWillUnmount 这三个函数的组合。 情况一不传第二个参数模拟 class 组件的 DidMount 和 DidUpdate
useEffect(() {
/** 执行逻辑 */
}) 情况二传递一个空数组模拟 class 组件的 DidMount
useEffect(() {
/** 执行逻辑 */
},[]) 情况三传递数组有依赖项模拟 class 组件的 DidUpdate
useEffect(() {
/** 执行逻辑 */
},[age,name]) 情况四第一个参数可以返回一个回调函数模拟 WillUnMount 组件销毁的时候 停止计时器
const [time, setTime] useState(0)
useEffect(() {const InterVal setInterval(() {setTime(time 1)},1000)return () {clearInterval(InterVal )}
},[])useMemo(calculateValue, dependencies)
useMemo是一个React Hook可以在重新渲染之间缓存计算结果。
import { useMemo } from react;function TodoList({ todos, tab }) {const visibleTodos useMemo(() filterTodos(todos, tab),[todos, tab]);// ...
}1、参数
calculateValue计算要缓存的值的函数。 dependencies:calculateValue代码内部引用的所有反应值的列表。
2、返回值
在初始呈现时useMemo返回不带参数的调用calculateValue的结果。 在接下来的渲染过程中它将返回上次渲染中已经存储的值如果依赖项没有更改或者再次调用calculateValue并返回calculateValue返回的结果。
3、用法
跳过昂贵的计算
4、怎样算昂贵的计算
一般来说除非您正在创建或循环数千个对象否则这可能并不昂贵。如果你想获得更多的信心你可以添加一个控制台日志来测量在一段代码中花费的时间
console.time(filter array);
const visibleTodos filterTodos(todos, tab);
console.timeEnd(filter array);如果记录的总时间加起来相当大比如1毫秒或更长那么将计算结果记忆起来可能是有意义的。作为实验您可以将计算结果封装在useMemo中以验证该交互的总记录时间是否减少。
5、何时使用useMemo
1、计算较慢并且依赖值很少变化 2、将该函数结果作为参数传给memo包裹的子组件 3、该结果作为其他hook的依赖项 在其他情况下将计算包装在useMemo中没有任何好处。这样做也没有重大危害所以一些团队选择不考虑个别案例并尽可能多地记忆。这种方法的缺点是代码的可读性变差
useState(initialState)
useState是一个React Hook它允许您将状态变量添加到组件中。
import { useState } from react;function MyComponent() {const [age, setAge] useState(28);const [name, setName] useState(Taylor);const [todos, setTodos] useState(() createTodos());// ...1、参数
initialState您希望状态初始为的值。它可以是任何类型的值但函数有一种特殊的行为。此参数在初始渲染后将被忽略。 如果将函数作为initialState传递它将被视为初始值设定项函数。
2、返回值
current state 当前状态在第一次渲染期间它将与您通过的initialState相匹配。 set函数用于将状态更新为不同的值并触发重新渲染。您可以直接传递下一个状态也可以传递根据上一个状态计算的函数
setName(Taylor);setAge(a a 1);3、用法
向组件添加状态React将存储下一个状态使用新值再次渲染组件并更新UI。
import { useState } from react;function MyComponent() {const [age, setAge] useState(42);const [name, setName] useState(Taylor);// ...4、定义对象
您可以将对象和数组置于状态。在React中状态被认为是只读的所以您应该替换它而不是突变现有的对象。
// Dont mutate an object in state like this:
form.firstName Taylor;
// ✅ Replace state with a new object
setForm({...form,firstName: Taylor
});5、避免传入函数调用结果为初始值 const [todos, setTodos] useState(createInitialTodos());尽管createInitialTodos的结果仅用于初始渲染但您仍在每次渲染时调用此函数。如果创建大型数组或执行昂贵的计算这可能是浪费。 const [todos, setTodos] useState(createInitialTodos);要解决此问题可以将其作为初始值设定项函数传递给useState您传递的是函数本身createInitialTodos而不是调用它的结果createInitialTodos。如果您将函数传递给useStateReact只会在初始化期间调用它。
useRef(initialValue)
useRef是一个React Hook它允许您引用渲染不需要的值。
mport { useRef } from react;function MyComponent() {const intervalRef useRef(0);const inputRef useRef(null);// ...1、参数
initialValue您希望ref对象的当前属性初始为的值。它可以是任何类型的值。此参数在初始渲染后将被忽略。
2、返回值
current最初它被设置为您传递的initialValue。您可以稍后将其设置为其他内容。
3、用法
①使用ref定义一个无需引起页面重新渲染的状态 改变一个ref的值不会触发重新渲染。这意味着引用非常适合存储不影响组件视觉输出的信息。
function handleStopClick() {const intervalId intervalRef.current;clearInterval(intervalId);
}②使用ref操作DOM
使用ref来操作DOM是特别常见的。React对此有内置支持。 首先声明一个初始值为null的ref对象
import { useRef } from react;function MyComponent() {const inputRef useRef(null);// ...return input ref{inputRef} /;React创建DOM节点并将其放在屏幕上后React将把ref对象的当前属性设置为该DOM节点。现在您可以访问input的DOM节点并调用focus等方法 ③ 避免重新创建引用内容 React将初始ref值保存一次并在下次渲染时忽略它。
function Video() {const playerRef useRef(new VideoPlayer());尽管新VideoPlayer的结果仅用于初始渲染但您仍在每次渲染时调用此函数。如果创建昂贵的对象这可能是浪费。 要解决此问题您可以按如下方式初始化ref
function Video() {const playerRef useRef(null);if (playerRef.current null) {playerRef.current new VideoPlayer();}// ...4、将ref传给自定义组件
默认情况下组件不会将其DOM节点公开给父组件这么写会报错
const inputRef useRef(null);
return MyInput ref{inputRef} /;如果您希望MyInput的父组件能够访问inputDOM节点则必须选择使用forwardRef
import { forwardRef } from react;const MyInput forwardRef(({ value, onChange }, ref) {return (inputvalue{value}onChange{onChange}ref{ref}/);
});export default MyInput;useImperativeHandle(ref, createHandle, dependencies?)
1、解释
React的useImperativeHandle是自定义钩子可以让父组件获取并执行子组件内某些自定义函数方法或者获取子组件的状态。
2、本质
useImperativeHandle本质上其实是子组件将自己内部的函数方法通过useImperativeHandle添加到父组件中useRef定义的对象中。如果想使用useImperativeHandle那么还要结合useRef、React.forwardRef一起使用。
3、示例
结合这个例子 使用forwardRef后父组件可以访问子组件的Dom
import { forwardRef } from react;const MyInput forwardRef(({ value, onChange }, ref) {return (inputvalue{value}onChange{onChange}ref{ref}/);
});export default MyInput;假设您不想公开整个inputDOM节点但希望公开它的两个方法focus和scrollIntoView。要做到这一点请将真实的浏览器DOM保存在一个单独的引用中。然后使用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} /;
});现在如果父组件获得对MyInput的引用它将能够调用其上的焦点和scrollIntoView方法。但是它将无法完全访问底层的inputDOM节点。