深入学习React Hook——useEffect

Hook使用规则

  • 只能在函数的最外层调用Hook,不能在循环、条件判断或子函数中调用。
  • 只能在React函数组件或自定义Hook中调用Hook,不可在其他JavaScript函数中使用。

useEffect一句话简介

useEffect相当于componentDidMount、componentDidUpdate、componentWillUnmount这三个生命周期方法的组合。

参数

参数1:函数,即effect

  • 函数体:执行各种副作用操作,如网络请求、添加订阅、添加计时器等。
  • 函数返回值:执行取消订阅、取消计时器等清理。

参数2:依赖项数组

  • 在依赖项数组中的effect需要引用值会改变外部变量,当它们的值改变时:
    1. 挂载阶段,effect函数体会在组件挂载后延迟一段时间被调用,相当于componentDidMount。
    2. 更新阶段,effect函数体会在组件更新后延迟一段时间被调用,相当于componentDidUpdate。
    3. 卸载阶段,effect函数返回值会在组件将要卸载前被调用,相当于componentWillUnmount。
  • 如果依赖项是空数组:
    1. 挂载阶段,effect函数体会在组件挂载后后延迟一段时间被调用,componentDidMount
    2. 更新阶段,effect函数体不会被调用,相当于componentDidUpdate。
    3. 卸载阶段,effect函数返回值会在组件将要卸载前被调用,相当于componentWillUnmount。
  • 如果effect使用的外部变量不在依赖项中,这些变量的值不会更新。
  • 值不会改变的外部变量不要加在依赖项中。例如React保证useState的更新函数不会改变,它们无需加入依赖数组。

如何区分变量是否会改变?

存放数据的变量是否会改变得看具体的代码才能确定;存放函数的变量是否会改变的规律总结如下:

  • useState的更新函数不会改变。
  • useCallback的返回值函数在依赖项不变的情况下不会改变。
  • 函数组件中的匿名函数和命名函数都会改变。

案例

import React, { memo, useCallback, useState } from "react";

type Style = {
  color: string;
  background: string;
};

const Show: React.FC<{ state: Style }> = (props) => {
  const { color, background } = props.state;
  console.log("Show");
  return (
    <div style={{ color, background }}>
      测试文字,文字的颜色和背景色可以切换!
    </div>
  );
};

const HandleColor: React.FC<{
  setState: React.Dispatch<React.SetStateAction<Style>>;
}> = memo((props) => {
  const { setState } = props;
  console.log("HandleColor");
  return (
    <button
      onClick={() =>
        // 更新函数和数据没放在一起,不易维护
        setState((preState) =>
          preState.color === "red"
            ? { ...preState, color: "blue" }
            : { ...preState, color: "red" }
        )
      }
    >
      点我改变颜色
    </button>
  );
});

const HandleBackground1: React.FC<{
  setBackground: () => void;
}> = memo((props) => {
  const { setBackground } = props;
  console.log("HandleBackground-1");
  return <button onClick={() => setBackground()}>点我改变背景</button>;
});

const HandleBackground2: React.FC<{
  setBackground: () => void;
}> = memo((props) => {
  const { setBackground } = props;
  console.log("HandleBackground-2");
  return <button onClick={() => setBackground()}>点我改变背景</button>;
});

const App = () => {
  const [state, setState] = useState<Style>({
    color: "red",
    background: "black"
  });
  console.log("渲染了App");
  const setBackground = useCallback(
    () =>
      setState((preState) =>
        preState.background === "black"
          ? { ...preState, background: "gray" }
          : { ...preState, background: "black" }
      ),
    []
  );
  const setBackground2 = () =>
    setState((preState) =>
      preState.background === "black"
        ? { ...preState, background: "gray" }
        : { ...preState, background: "black" }
    )
  return (
    <>
      <Show state={state} />
      <HandleColor setState={setState} />
      <HandleBackground1 setBackground={setBackground} />
      <HandleBackground2 setBackground={setBackground2} />
    </>
  );
};

export default App;

在线体验
仔细看console.log打印的日志,点击HandleBackground1按钮时,只会提示“HandleBackground-2”,这说明HandleBackground2组件收到的props发生了改变,而HandleBackground1组件收到的props未发生改变。

建议

  • 在涉及多个业务逻辑的复杂组件中,建议按业务逻辑拆分useEffect,这样可以提高代码可维护性。
    例如:某组件需要向2个API接口分别请求数据,此时就应该分开写在2个useEffect中,而不应集中写在一个useEffect中。这样以后遇到某个API接口有变动需要改代码时,分开写useEffect比集中写会更方便维护。
  • 集中在一起的useEffect与按业务逻辑拆成多个的useEffect相比运行效率几乎没差别,拆分useEffect不会导致额外的渲染。
  • 条件判断不能写在effect函数外面,必须写在effect函数内部。

代码片段

2022-04-25_15-35.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值