学习(更多)挂钩=赚钱!
我们又回来了,使更多的dinero!ðµðµð µ
让我们探索一些不常用的,但在React中仍然是最重要的钩子!
所有示例的代码都可以在此Code Sandbox中找到。
这是三部分系列的第2部分,它涵盖用户ducer , useref , usememo , usecallback , 使用刺激性和 uselayouteffect !
UserDucer
-
useReducer
可以用作useState
的替代方案。 - “当您具有涉及多个子值的复杂状态逻辑或下一个状态取决于上一个状态时,用户deper通常比Usestate更可取。”
-
示例:
// /src/UseReducerExample.js import { useReducer } from "react"; import { Link } from "react-router-dom"; const bankBalance = { counter: 0 }; function reducer(state, action) { switch (action.type) { case "make 1 $": return { counter: state.counter + 1 }; case "spend 1 $": return { counter: state.counter - 1 }; default: throw new Error(); } } export default function UseReducerExample() { const [state, dispatch] = useReducer(reducer, bankBalance); return ( <> <h1> <Link to={"/"}> Dinero! </Link> </h1> <h2> {state.counter >= 0 ? "You have" : "You lost"} {Math.abs(state.counter)}{" "} 💵 </h2> <button onClick={() => dispatch({ type: "spend 1 $" })}>Spend 1 $</button> <button onClick={() => dispatch({ type: "make 1 $" })}>Make 1 $</button> </> ); }
-
在上面的示例中:
-
useReducer
挂钩接受reducer
函数和要保存的数据, 在此,{counter:0} 。 -
useReducer
挂钩返回包含此数据的state
对象和dispatch
函数。 - 当
dispatch
用action
调用时,{type:“ onceed 1 $”} , - 它将
state
和此action
传递到reducer
函数。 - 根据
action
类型,它将返回一些值,并且此值将保存到state
此处,state.counter - 然后可以在组件内访问状态的更新值。
-
useref
-
useRef
钩可用于引用给定值,它将存储在零件重新租赁之间的.current
属性中,并且可以更改。 - 一个常见的用例是直接访问DOM元素。
- 重要的是要注意,突变
.current
不会引起重新渲染。 -
示例:
// /src/UseRefExample.js import { useRef } from "react"; import { Link } from "react-router-dom"; export default function UseRefExample() { let counter = 0; const refAmt = useRef(null); const updateAmt = () => { console.log(refAmt.current); counter += 1; console.log(`You actually have ${counter} 💵`); }; return ( <> <h1> <Link to={"/"}> Dinero! </Link> </h1> <h2 ref={refAmt}>You have {counter} 💵</h2> <button onClick={updateAmt}>Get 1 $</button> </> ); }
-
在上面的示例中:
- 我们创建了一个参考,
refAmt
。 - 在
<h2>
元素中,我们指定了ref={refAmt}
,因此refAmt.current
指向<h2>
元素。 - 单击按钮,我们可以打开控制台并查看
-
counter
的价值正在增加。 - 但是,
refAmt.current
(指向<h2>
元素)没有使用counter
的新值进行更新。
- 我们创建了一个参考,
- 上看到它
被订购
-
useMemo
挂钩采用功能(理想情况下返回某些东西)和一系列依赖项。 - 只有一个或多个依赖项已更改,它才会重新计算返回值。
- 这有助于对每个渲染的优化计算,这可能不一定需要重新计算。
- 如果不提供数组,则将在每个渲染上计算一个新值。
- 该函数中引用的每个值也应出现在依赖项数组中。
- 副作用应在
useEffect
中,而不是useMemo
。 -
示例:
// /src/UseMemoExample.js import { useState, useMemo } from "react"; import { Link } from "react-router-dom"; function calculationRes(constant) { const result = constant ** 2; console.log(`The calculated result is: ${result}`); return result; } export default function UseMemoExample() { const [counter, setCounter] = useState(0); const [constant] = useState(1000000); const calculation = useMemo(() => calculationRes(constant), [constant]); return ( <> <h1> <Link to={"/"}> Dinero! </Link> </h1> <h2>You have {counter} 💵</h2> <button onClick={() => setCounter(counter + 1)}>Get 1 $</button> {calculation} </> ); }
-
在上面的示例中:
- 函数
calculationRes
运行一次,结果被记忆,result
登录控制台。 - 单击按钮时,状态
counter
更改,因此组件重新租赁。 - 但在随后的渲染中,
result
未记录到控制台。 - 这是因为
result
的值没有更改,因为变量constant
的值没有更改,这是calculationRes
的依赖项数组。
- 函数
- 中看到它
usecallback
-
useCallback
钩与useMemo
钩非常相似,唯一的区别是useMemo
返回了回忆的值,而useCallback
返回了回忆的功能。 - 一个常见的用例是需要将函数传递到嵌套子组件时。
-
可以通过更换:
来引用上面的示例,作为useCallback
的示例const calculation = useMemo(() => calculationRes(constant), [constant]);
与
const calculation = useCallback(() => calculationRes(constant), [constant]);
- 上看到它
forwardref 和使用刺激性
- 正如我们上面看到的,
useRef
钩可用于访问DOM元素。 - 我们可以包裹组件公开此
ref
,在forwardRef
内部,然后父组件可以访问此参考文献 -
转发参考的示例:
import { useRef, forwardRef } from "react"; function ChildComponent(props, ref) { return ( <> <h1 ref={ref} {...props}>{"💵💵💵💵💵💵💵💵💵💵"}</h1> </> ); } ChildComponent = forwardRef(ChildComponent); export default function UseImperativeHandleExample() { const moneyRef = useRef(null); return ( <> <ChildComponent ref={moneyRef} /> </> ); }
-
在上面的示例中:
- 父组件
UseImperativeHandleExample
使用useRef
钩创建ref对象。 - 此裁判指向
ChildComponent
。 -
ChildComponent
包裹在forwardRef
中,因此我们可以将此参考对象分配给其中的dom元素,在此,<h1> element
。 - 现在,父组件
UseImperativeHandleExample
可以访问ref toChildComponent
内的<h1> element
。
- 父组件
-
现在,如果我们需要根据某些用户操作来修改此参考的行为,这就是
useImperativeHandle
钩子派上用场的地方! -
上面的示例可以像这样修改:
// /src/UseImperativeHandleExample.js import { useRef, forwardRef, useImperativeHandle } from "react"; import { Link } from "react-router-dom"; function ChildComponent(props, ref) { const h1Ref = useRef(null); useImperativeHandle(ref, () => ({ seeReferencedEl: h1Ref.current })); return ( <> <h1> <Link to={"/"}> Dinero! </Link> </h1> <h1 ref={h1Ref} {...props}> {"💵💵💵💵💵💵💵💵💵💵"} </h1> </> ); } ChildComponent = forwardRef(ChildComponent); export default function UseImperativeHandleExample() { const moneyRef = useRef(null); const seeReferencedElement = () => { console.log(moneyRef.current?.seeReferencedEl); }; return ( <> <ChildComponent ref={moneyRef} /> <button onClick={seeReferencedElement}>See ref in console</button> </> ); }
-
在上面的示例中:
- 在
UseImperativeHandleExample
组件内,moneyRef.current
指向ChildComponent
,如我们在 forwardref 示例之前所见。 - 但是在此示例中,我们将一个新的REF对象分配给
ChildComponent
中的<h1> element
。 - 使用
useImperativeHandle
钩,我们将此新的h1Ref
分配给ChildComponent
Ref的seeReferencedEl
属性 - 所以,现在,在
UseImperativeHandleExample
组件内,moneyRef.current.seeReferencedEl
指向<h1> element
的ChildComponent
。
- 在
USELAYOUTEFFECT
-
useLayoutEffect
与useEffect
相似,除了一个关键区别。 - 在将元素加载到DOM之后,但在将它们涂成UI之前,它将(同步)运行。
- “使用此[挂钩]从DOM读取布局并同步重新渲染”。
- 一个常见的用例是测量布局并基于它更改元素的位置。
-
示例:
// /src/UseLayoutEffectExample.js import { useRef, useEffect, useLayoutEffect } from "react"; import { Link } from "react-router-dom"; export default function UseLayoutEffectExample() { const refAmt = useRef(null); useEffect(() => { console.log("useEffect called!"); }, []); useLayoutEffect(() => { console.log("useLayoutEffect called"); }, []); return ( <> <h1> <Link to={"/"} style={styles.linkStyle}> Dinero! </Link> </h1> <h2 ref={refAmt}>You have 1000000 💵</h2> </> ); }
-
在上面的示例中:
- 我们看到
"useLayoutEffect called"
首先记录了,因为useLayoutEffect
同步运行 - 然后在视觉上更新DOM。
- 然后,
"useEffect called!"
被记录,因为useEffect
异步运行。
- 我们看到
希望您有一个有趣的学习挂钩,并很快前往Buggati商店进行周日购物!
请继续关注第3部分,我们查看更多hooksðä
欢呼!