React之Hooks

一、Hooks 是什么?

  • Hooks 是 React 16.8 引入的新特性,让函数组件也能使用 state生命周期上下文 等能力。

  • 核心优势

    1. 逻辑复用更方便(自定义 Hook)。

    2. 函数组件写法更简洁。

    3. 不再依赖类组件的复杂 this

二、常用 Hooks

 1. useState

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <>
      <p>点击次数:{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </>
  );
}
  • 初始值:0

  • 更新值:setCount(newValue)

  • 每次调用 setCount 会触发 组件重新渲染

2. useEffect

处理 副作用(如网络请求、DOM 操作、定时器)。

import { useEffect, useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  // 挂载 + 更新
  useEffect(() => {
    console.log("组件更新/挂载:", count);
  }, [count]);

  // 挂载 + 卸载
  useEffect(() => {
    const timer = setInterval(() => console.log("运行中..."), 1000);
    return () => clearInterval(timer); // 卸载时清理
  }, []);

  return <button onClick={() => setCount(count + 1)}>+1</button>;
}

注意:

  • [] 表示只运行一次(挂载/卸载)。

  • [count] 表示依赖更新时才触发。

  • 不写依赖 → 每次渲染都会运行。

3. useContext

import { createContext, useContext } from "react";

const ThemeContext = createContext("light");

function Child() {
  const theme = useContext(ThemeContext);
  return <p>主题:{theme}</p>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  );
}

跨组件共享状态(替代繁琐的 props 传递)

4. useReducer

import { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+1</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-1</button>
    </>
  );
}

         管理复杂状态,类似 Redux

        用于:

  • 状态逻辑复杂。

  • 状态更新依赖前一个状态

5. useRef

import { useRef, useEffect } from "react";

function InputFocus() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus(); // 自动聚焦
  }, []);

  return <input ref={inputRef} />;
}

 获取 DOM 节点 / 保存不触发渲染的值

  • useRef 返回一个 可变对象 { current: ... }

  • 修改 .current 不会触发重新渲染】

6. useMemo

import { useMemo, useState } from "react";

function ExpensiveCalc({ num }) {
  const result = useMemo(() => {
    console.log("计算中...");
    return num * 2;
  }, [num]);

  return <p>结果:{result}</p>;
}

缓存计算结果,避免重复计算

 场景:

  • 大量计算

  • 避免每次渲染都重新算

7. useCallback

import { useState, useCallback } from "react";

function Child({ onClick }) {
  console.log("子组件渲染");
  return <button onClick={onClick}>子按钮</button>;
}

function App() {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => {
    console.log("点击子组件按钮");
  }, []); // 依赖变化才生成新函数

  return (
    <>
      <p>{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <Child onClick={handleClick} />
    </>
  );
}

缓存函数引用,避免子组件重复渲染

搭配 React.memo 使用,避免不必要的渲染

8. useLayoutEffect

useEffect 类似,但在 DOM 更新后、浏览器绘制前 同步执行。

  • 常用于:需要获取更新后的 DOM 位置/大小

  • ⚠️ 谨慎使用,可能阻塞渲染

9. useImperativeHandle

import { useImperativeHandle, forwardRef, useRef } from "react";

const Child = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    focus: () => console.log("子组件方法调用")
  }));
  return <p>子组件</p>;
});

function App() {
  const childRef = useRef();
  return (
    <>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.focus()}>调用子方法</button>
    </>
  );
}

forwardRef 中自定义暴露给父组件的 ref

三、自定义 Hook

例如:

import { useState, useEffect } from "react";

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []);
  return width;
}

function App() {
  const width = useWindowWidth();
  return <p>窗口宽度:{width}</p>;
}

四、Hooks 使用规则(重要)

  1. 只能在函数组件或自定义 Hook 顶层调用,不能写在条件、循环里

  2. 不要在普通函数里用 Hooks

  3. 依赖项要写全(用 ESLint 插件 eslint-plugin-react-hooks 检查)

五、React 生命周期

一、类组件生命周期阶段

React 类组件有三个主要阶段:

  1. 挂载(Mounting):组件被创建并插入到 DOM 中

  2. 更新(Updating):props 或 state 改变导致重新渲染

  3. 卸载(Unmounting):组件从 DOM 中移除

二、示例

1. 挂载阶段

import { useState, useEffect } from "react";

function App() {
  const [count, setCount] = useState(0); // 类似 constructor 初始化

  // 类似 componentDidMount
  useEffect(() => {
    console.log("组件挂载");
  }, []);

  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

2. 更新阶段

useEffect(() => {
  console.log("count 更新了:", count);
}, [count]); // 依赖更新时触发,类似 componentDidUpdate
性能优化(类似 shouldComponentUpdate):


const Child = React.memo(({ onClick }) => {
  console.log("子组件渲染");
  return <button onClick={onClick}>子组件按钮</button>;
});

const App = () => {
  const [count, setCount] = useState(0);
  const handleClick = useCallback(() => {
    console.log("点击");
  }, []);
  return <Child onClick={handleClick} />;
};

3. 卸载阶段



useEffect(() => {
  const timer = setInterval(() => console.log("运行中..."), 1000);

  // 返回函数相当于 componentWillUnmount
  return () => {
    clearInterval(timer);
    console.log("组件卸载");
  };
}, []);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值