React Hooks 那些事儿

翻了波之前写的文章还有笔记,发现关于前端的文章并不多(好歹也划水做过点前端开发)。巧了,最近没什么好话题可写,做下 React Hooks 学习笔记吧。

Effect Hook

不得不说 Hook 的出现降低了我们在 React 中处理副作用(side effect)的心智负担,通过 useEffect 就可以很好的完成之前需要使用几个生命周期函数配合才能完成的事。

Effect Hook 死循环请求问题

由于 Effect Hook 不熟「官方文档没读透」,最近使用 useEffect 出现了异步请求发送了无限次的问题,翻🚗了。我有个组件大概是这么写的:

jsx 复制代码
import React, { useState, useEffect } from 'react';

import request from 'umi-request';

import logo from './logo.svg';
import './App.css';

function App() {
  const [data, setData] = useState([]);

  useEffect(() => {
    request('https://jsonplaceholder.typicode.com/todos/', {
     method: 'get',
    })
    .then(response => {
      console.log('fetch data');
      setData(response);
    })
    .catch(error => {
      console.log("report error: ", error);
    })
  });

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <ul>
          {data.map(item => {
            return (
            <li key={item.id}>{item.title}</li>
            );
          })}
        </ul>
      </header>
    </div>
  );
}

export default App;

效果如下:

{% iframe https://codesandbox.io/embed/nice-sea-zo2c2?fontsize=14&hidenavigation=1&theme=dark 100% 500 %}

{% gallery %} {% endgallery %}

https://zo2c2.csb.app/,可以很方便的从调试控制台看到,异步请求一直在发,陷入了死循环之中。这是为什么?因为 useEffect 会在组件 Mounting 和 Updating 阶段执行。每次 request 请求成功,我们都会设置一次组件的 state -> data,所以组件会更新,useEffect 会再次执行,循环往复,造成了无限重复请求问题。那么,如何解决这个问题?之前我忽略了 useEffect 第二个参数的存在,使用 useEffect 的第二个参数可以解决这个问题。一般情况下,我们希望组件只在 mounting 阶段异步获取数据,所以,我们可以这么设置 useEffect 的第二个参数,让它具有和 componentDidMount 生命周期函数类似的行为(组件第一次 mount 后执行):

{% folding red open, React 组件生命周期 %}

来源:https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

{% endfolding %}

{% codeblock lang:jsx line_number:true mark:7,12 %} useEffect(() => { request('https://jsonplaceholder.typicode.com/todos/', { method: 'get', }) .then(response => { console.log('fetch data'); setData(response); }) .catch(error => { console.log("report error: ", error); }) }, []); {% endcodeblock %}

我们传递了一个空数组作为 useEffect 的第二个参数,这样就能避免在组件 Updating 阶段执行 useEffect。这个数组成为依赖数组。依赖数组为空,表明 useEffect 不会因为某个变量的变化而再次执行。在组件需要根据某个变量变化进行渲染的时候,可以将此变量放到依赖数组中,一旦这个依赖的变量变动,useEffect 就会重新执行。

让组件卸载后做点事

在 class 组件中,我们可以将组件卸载后要做的事放在 componentWillUnmount 中。引入 Hook 后,在 function 组件中,我们可以把组件卸载要做的事放在 useEffect 中,让它返回一个 callback 即可,如下:

jsx 复制代码
import React, { useState, useEffect } from "react";

function Child({ visible }) {
  useEffect(() => {
    alert("组件已挂载");
    return () => {  // return 一个 callback
      alert("组件已被卸载!!");
    };
  }, []);

  return visible ? "true" : "false";
}

export default function App() {
  const [visible, changeVisible] = useState(true);

  return (
    <div>
      {visible && <Child visible={visible} />}
      <button
        onClick={() => {
          changeVisible(!visible);
        }}
      >
        {visible ? "卸载组件" : "挂载组件"}
      </button>
    </div>
  );
}

{% iframe https://codesandbox.io/embed/condescending-minsky-jnzcc?fontsize=14&hidenavigation=1&theme=dark 100% 500 %}

{% gallery %} {% endgallery %}

参考

相关推荐
秋邱2 小时前
高等教育 AI 智能体的 “导学诊践” 闭环
开发语言·网络·数据库·人工智能·python·docker
芥子沫3 小时前
日记应用推荐-Docker安装DailyNotes应用
docker·容器·日记
贝锐12 小时前
Docker部署Teemii本地漫画库,并通过花生壳内网穿透实现远程访问
docker
i***220715 小时前
springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice
spring boot·后端·docker
羑悻的小杀马特17 小时前
轻量跨云·掌控无界:Portainer CE + cpolar 让远程容器运维像点外卖一样简单——免复杂配置,安全直达对应集群
运维·网络·安全·docker·cpolar
一念一花一世界20 小时前
DevOps实战(11) - 使用Arbess+Hadess实现下载制品进行主机部署
ci/cd·jar·devops·arbess·hadess
y***866921 小时前
DevOps在云中的自动化部署
运维·自动化·devops
运维-大白同学21 小时前
2025最全面开源devops运维平台功能介绍
linux·运维·kubernetes·开源·运维开发·devops
EAIReport1 天前
企业级报表自动化:基于Docker的部署实践
运维·docker·自动化
1***y1781 天前
DevOps在云中的Rancher
运维·rancher·devops