React Hooks 👈| 自变量与因变量思想| 自顶向下学习🚀🚀🚀

346 阅读4分钟

前言

跟着卡颂大佬自顶向下学习 React Hooks 的核心思想 , 从自变量与因变量的角度,来深入理解React Hooks的核心概念 ~

自变量与因变量:React Hooks的核心

在数学中,自变量的变化会导致因变量的变化。

比如 2*x + 1 = y

类似地,在React组件中,状态(state)的变化会触发视图(view)的更新。

我们可以这样看待 React Hooks

这种从自变量到因变量的关系在React Hooks中体现得淋漓尽致。

useState:自变量引发视图变化

useState是React Hooks中最基本的Hook。它允许我们在函数组件中声明一个状态变量。当状态变量发生变化时,组件会重新渲染,就像自变量的变化导致因变量的变化一样。

import { useState } from "react";

export default function App() {
  const [x, setX] = useState(0);
  const y = 2 * x + 1;
  const changeX = () => setX(x + 1);

  return (
    <ul onClick={changeX}>
      <li>x是{x}</li>
      <li>y是{y}</li>
    </ul>
  );
}

在这个例子中,x是自变量,y是因变量。当x发生变化时,y也会随之变化,并且视图会更新为新的y值。

useMemo与useCallback:缓存因变量与函数

在某些情况下,我们希望避免不必要的计算,尤其是当计算成本较高时。useMemouseCallback就是为此而生的。

  • useMemo用于缓存计算结果
  • useCallback用于缓存函数。

import { useState, useMemo, useCallback } from "react";

export default function App() {
  const [x, setX] = useState(0);
  const y = useMemo(() => 2 * x + 1, [x]);
  const changeX = useCallback(() => setX(x + 1), [x]);

  return (
    <ul onClick={changeX}>
      <li>x是{x}</li>
      <li>y是{y}</li>
    </ul>
  );
}

代码中

  • useMemo包裹了因变量y
  • useCallback包裹了函数changeX

它们都需要显式地指定依赖的自变量。当依赖的自变量 [x] 没有变化时,ychangeX都会直接从缓存中读取,而不是重新计算或创建。

需要注意的是,虽然这两个Hook可以优化性能,但在很多情况下,如果不涉及复杂的计算或频繁的更新,直接使用普通的函数组件也是可以的。

useEffect:处理副作用

副作用是指函数的输出不仅取决于输入,还依赖于其他外部因素。

比如以下函数 , 输入 X , 我们可以得到固定的输出 , 只要 X 确定 , Y 便可以确定 , 这样的函数称之为纯函数

比如以下函数 , 当 X 确定的时候 , 收到 Math.random() 的影响 , 无法确定 Y 的值 , 这个就是副作用

在React中,副作用通常包括数据请求、DOM操作等。useEffect就是用来处理这些副作用的。

    import { useState, useEffect } from "react";
    
    // 定义 Count 组件的 props 类型
    interface CountProps {
      data: number;
    }
    
    // 使用定义好的类型
    const Count = ({ data }: CountProps) => {
      return <span>{data}</span>;
    };
    
    export default function App() {
      const [x, setX] = useState(0);
      const y = 2 * x + 1;
      const changeX = () => setX(x + 1);
    
      useEffect(() => {
        document.title = String(x); // 将 x 转换为字符串
      }, [x]);
    
      return (
        <ul onClick={changeX}>
          <li>x是<Count data={x} /></li>
          <li>y是<Count data={y} /></li>
        </ul>
      );
    }

在这个例子中,当x发生变化时,useEffect会执行,将页面标题设置为x的值。这种操作属于副作用,因为它改变了组件外部的状态

useContext:跨组件传递数据

在多层组件嵌套的情况下,将数据从顶层组件传递到底层组件可能会非常繁琐。useContext提供了一种更简洁的解决方案。

比如上面的序号 1 组件到 序号 2 组件 , 需要把自变量从第一级组件跑到第四级组件 , 十分繁琐 , 于是我们使用 useContext

const CountContext = createContext();

function App() {
  const [count, setCount] = useState(0);
  return (
    <CountContext.Provider value={count}>
      <ChildComponent />
    </CountContext.Provider>

  );
}

function ChildComponent() {
  const count = useContext(CountContext);
  return <div>{count}</div>;
}

在这个例子中,App组件通过CountContext.Providercount传递给ChildComponent,而ChildComponent可以直接通过useContext获取count,而无需逐层传递。

到此剩下 useRef , 作为自变量和因变量的 hooks 组件总结如下 :

useRef:缓存数据

有时候,我们需要在组件中缓存一些数据,这些数据既不是状态变量,也不需要触发视图更新。useRef就是用于这种场景的。

const countRef = useRef(0);

useEffect(() => {
  countRef.current += 1;
  if (countRef.current % 2 === 0) {
    document.title = x;
  }
}, [x]);

在这个例子中,countRef用于缓存一个计数器。每次组件渲染时,countRef.current会增加1。当计数器为偶数时,页面标题会被设置为x的值。useRef提供了一个可变的引用,不会触发组件的重新渲染。