React 新手踩坑之旅 — Hook篇

illustration of React State and Hook

开始学习 React 开发

随着 Claude Sonnet 3.5、DeepSeek V2、GPT-4o 这些模型的推出,模型在 AI Coding 领域的质量大幅提升。同时 Cursor 这个 IDE 工具的火爆,极大的降低了 Coding 的门槛,也激发了我上手写代码做项目的热情。

于是,我开始做一个 AI 自动摘要 arXiv 论文的网站项目。前端采用了 React 框架,因为它的生态成熟,有大量现成的组件、高级框架可以直接使用,例如:

  • 开发框架:Next.js
  • UI 组件:shadcn/ui
  • 登录组件:NextAuth.js

于是,借助 Cursor + DeepSeek,安装 Node 开发环境,初始化 NextJS 项目,初始化 Shadcn/ui 组件,很快就完成了项目的初始版本,项目可以运行起来了。

然而,想要加上 Search 搜索框,就遇到了各种问题,即使通过给 DeepSeek 提要求、贴 Bug 能暂时解决部分问题,但还是因为不理解 React 中的各种 Hook 机制 — useState / useEffect,导致相同的问题还会遇到,遇到问题还会手足无措。

AI 可以为我生成代码、做出项目,但没有让我学会写代码、Debug。

React 中的 Hook

使用 React 首先要理解 React 的原理。

  • react component:React 定义的一套对象,存储在浏览器,但它不是浏览器 DOM
  • react-dom:把 react component 更新到浏览器 DOM 里。按需更新,只更新 diff,以提升性能

State 和 Hook

React component 中使用 state 来保存数据,通过 useState 这个 hook 来声明 state,通过 setXXX 来更新 state 的状态。

import React, { useState } from 'react';

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

  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

export default App;

UI 界面的用户交互

UI 界面需要跟用户交互,当产生用户事件后(例如输入表单、滚动页面等等),首先在页面上需要以 UI 变化来及时反馈给用户,UI 的变化需要由 react component 的 state 变化来触发。

因此需要声明一个(很可能是多个)state 来保存用户交互的内容,通过浏览器事件、表单输入事件等等触发执行 setXXX 这个 hook 来更新 state。

此时:用户交互 -> state 变化 -> react dom 更新浏览器 DOM,这个过程中每个步骤都是异步的,但速度很快。

与服务端交互

用户的交互通常需要触发与服务端通信(例如取数据),因此需要在 state 变化时触发副作用,即:useEffect。

useEffect 需要监听一个(或多个) state 的变化,来触发执行。

function App() {
  const [data, setData] = useState({ hits: [] });
  const [query, setQuery] = useState('redux');

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios(
        `http://hn.algolia.com/api/v1/search?query=${query}`,
      );

      setData(result.data);
    };

    fetchData();
  }, [query]);

  return (
    ...
  );
}

export default App;

而通常服务端通信速度慢,为了让用户感知到「正在执行用户操作」(正在与服务端通信),又需要定义一个 state 来保存通信状态,通常是「loading」状态。

与服务端通信完成后,通常会自己更新保存数据的一个 state 并关闭 loading 状态,会异步触发浏览器 DOM 更新。

学习收获

React 在前端项目中用于保存和反应 UI 状态的变化,用户的交互、UI 状态的刷新等等都是异步事件,react component 中需要记住这种异步性。

同时为了即时响应用户的交互、提升用户的体验,需要把涉及异步服务端请求的行为通过 useEffect 来触发、异步化,同时设置异步状态的 state 来反馈给用户

我参考的资料

这篇文章从 0 开始讲诉,如何一步步的使用 hook、获取 api 数据、展示在页面,非常浅显易懂

https://www.robinwieruch.de/react-hooks-fetch-data

这篇文章讲为什么 React 没有立即更新 state

https://blog.logrocket.com/why-react-doesnt-update-state-immediately/

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *