返回文章
React约 3 分钟阅读

React 状态少一点,组件清楚一点

筛选后的列表需要放进 state 吗?从派生数据出发,减少重复状态与不必要的 Effect。

GUAN前端开发手记
示例文章

收藏保存在此浏览器,可在归档页查看。

文章目录4 个章节

当组件里出现两个必须保持一致的 state,先停下来问一句:其中一个是否可以由另一个算出来?这往往是简化组件最直接的切入点。

找到真正会变化的输入

文章列表的输入是文章集合和搜索词。筛选结果可以在渲染时计算,不需要再保存一份。

import { useState } from 'react';

export function ArticleSearch({ articles }) {
  const [query, setQuery] = useState('');
  const normalizedQuery = query.trim().toLowerCase();
  const visibleArticles = articles.filter(article =>
    article.title.toLowerCase().includes(normalizedQuery)
  );

  return (
    <section>
      <label>
        搜索文章
        <input
          value={query}
          onChange={event => setQuery(event.target.value)}
        />
      </label>
      <ul>
        {visibleArticles.map(article => (
          <li key={article.id}>{article.title}</li>
        ))}
      </ul>
    </section>
  );
}

这个组件只有一份用户输入。文章集合更新或搜索词改变时,筛选结果自然会随渲染重新计算,不需要额外 Effect 来同步。

Effect 留给外部同步

Effect 适合把组件与外部系统同步,例如注册浏览器事件、建立连接或控制非 React 组件。单纯从现有 props 和 state 得到另一个值,通常不需要 Effect。

用 Effect 更新派生状态,会先产生一次携带旧结果的渲染,再触发额外的更新;更麻烦的是依赖列表遗漏时,数据会悄悄变旧。

useMemo 是优化工具

如果筛选规模确实很大,可以测量耗时,再考虑用 useMemo 缓存计算。它不应该成为保证业务正确性的前提,也不是所有数组操作的必备包装。

先保证代码直接、数据流单向,再依据性能记录优化。少一份状态,就少一条需要人工维护的同步关系。

一个实用检查

新增 state 前检查三件事:它是否来自用户输入或外部系统?它是否能由已有数据推导?如果已有数据改变,它是否还需要手动同步?最后一个问题经常能暴露重复状态。

读到这里,不妨动手试一试。
把一个概念变成能运行的小实验。

找一篇笔记

输入关键词,或浏览全部文章。

按 Tab 选择文章Esc 关闭