示例钩子 - 第2部分
#javascript #网络开发人员 #react #hooks

学习(更多)挂钩=赚钱!

我们又回来了,使更多的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函数。
    • dispatchaction 调用时,{type:“ onceed 1 $”}
    • 它将state和此action传递到reducer函数。
    • 根据action类型,它将返回一些值,并且此值将保存到state 此处,state.counter
    • 然后可以在组件内访问状态的更新值。
  • here和此sandbox中的代码中看到它!


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的新值进行更新。
  • here和此sandbox

  • 上看到它

被订购

  • 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的依赖项数组。
  • here和此sandbox

  • 中看到它

usecallback

  • useCallback钩与useMemo钩非常相似,唯一的区别是useMemo返回了回忆的值,而useCallback返回了回忆的功能。
  • 一个常见的用例是需要将函数传递到嵌套子组件时。
  • 可以通过更换:

    来引用上面的示例,作为useCallback的示例 const calculation = useMemo(() => calculationRes(constant), [constant]);

    const calculation = useCallback(() => calculationRes(constant), [constant]);
    
  • here和此sandbox

  • 上看到它

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 to ChildComponent内的<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> elementChildComponent
  • here和此sandbox中的代码中看到它!


USELAYOUTEFFECT

  • useLayoutEffectuseEffect相似,除了一个关键区别。
  • 在将元素加载到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异步运行。
  • sandbox中的here和代码中看到它!

希望您有一个有趣的学习挂钩,并很快前往Buggati商店进行周日购物!
请继续关注第3部分,我们查看更多hooksðä
欢呼!