[{"data":1,"prerenderedAt":242},["ShallowReactive",2],{"article-react-use-effect-notes":3,"related-articles":141},{"id":4,"title":5,"body":6,"categoryLabel":126,"categorySlug":127,"description":128,"extension":129,"featured":130,"meta":131,"navigation":132,"path":133,"publishedAt":134,"readingMinutes":135,"seo":136,"stem":137,"tags":138,"__hash__":140},"blog\u002Fblog\u002Freact-use-effect-notes.md","React useEffect 的依赖和清理",{"type":7,"value":8,"toc":121},"minimark",[9,17,21,24,27,108,111,114,117],[10,11,12,16],"p",{},[13,14,15],"code",{},"useEffect"," 用来让组件和外部系统同步，例如订阅事件或启动定时器。它不适合替代所有状态计算；能在渲染时直接得到的值，通常不需要再放进 effect。",[18,19,20],"h2",{"id":20},"依赖项说明同步关系",[10,22,23],{},"依赖数组列出 effect 使用到、并且可能变化的响应式值。依赖变化后，React 会先运行上一次的清理函数，再运行新的 effect。",[18,25,26],{"id":26},"清理外部资源",[28,29,34],"pre",{"className":30,"code":31,"language":32,"meta":33,"style":33},"language-tsx shiki shiki-themes github-light-high-contrast","useEffect(() => {\n  const timer = window.setInterval(refresh, 5000)\n  return () => window.clearInterval(timer)\n}, [refresh])\n","tsx","",[13,35,36,55,83,102],{"__ignoreMap":33},[37,38,41,44,48,52],"span",{"class":39,"line":40},"line",1,[37,42,15],{"class":43},"s3dhs",[37,45,47],{"class":46},"sigWx","(() ",[37,49,51],{"class":50},"sTJeM","=>",[37,53,54],{"class":46}," {\n",[37,56,58,61,65,68,71,74,77,80],{"class":39,"line":57},2,[37,59,60],{"class":50},"  const",[37,62,64],{"class":63},"sacAq"," timer",[37,66,67],{"class":50}," =",[37,69,70],{"class":46}," window.",[37,72,73],{"class":43},"setInterval",[37,75,76],{"class":46},"(refresh, ",[37,78,79],{"class":63},"5000",[37,81,82],{"class":46},")\n",[37,84,86,89,92,94,96,99],{"class":39,"line":85},3,[37,87,88],{"class":50},"  return",[37,90,91],{"class":46}," () ",[37,93,51],{"class":50},[37,95,70],{"class":46},[37,97,98],{"class":43},"clearInterval",[37,100,101],{"class":46},"(timer)\n",[37,103,105],{"class":39,"line":104},4,[37,106,107],{"class":46},"}, [refresh])\n",[10,109,110],{},"组件卸载或依赖变化时，清理函数会释放定时器。订阅事件、WebSocket 连接也应遵循同样的清理思路。",[18,112,113],{"id":113},"排查依赖问题",[10,115,116],{},"遇到重复请求或旧数据时，先检查 effect 真正依赖哪些值，再考虑是否能把逻辑移到事件处理函数或使用更合适的数据请求方式。",[118,119,120],"style",{},"html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":33,"searchDepth":57,"depth":57,"links":122},[123,124,125],{"id":20,"depth":57,"text":20},{"id":26,"depth":57,"text":26},{"id":113,"depth":57,"text":113},"React","react","整理 useEffect 何时运行，以及订阅和定时器为什么需要清理。","md",false,{},true,"\u002Fblog\u002Freact-use-effect-notes","2026-06-30",6,{"title":5,"description":128},"blog\u002Freact-use-effect-notes",[126,15,139],"学习笔记","FQuey6mNNSlw3seqp1S9_aA_7WRTMn9DwqCu601sajo",[142,154,164,172,180,188,196,198,206,216,224,232],{"id":143,"path":144,"title":145,"description":146,"categorySlug":147,"categoryLabel":148,"publishedAt":149,"readingMinutes":104,"featured":132,"tags":150},"blog\u002Fblog\u002Fcss-grid-cards.md","\u002Fblog\u002Fcss-grid-cards","用 CSS Grid 排列自适应卡片","使用 repeat、minmax 和 auto-fit，让卡片列数随容器宽度自然变化。","styles","页面与样式","2026-09-10",[151,152,153],"CSS","Grid","页面布局",{"id":155,"path":156,"title":157,"description":158,"categorySlug":147,"categoryLabel":148,"publishedAt":159,"readingMinutes":160,"featured":130,"tags":161},"blog\u002Fblog\u002Fmobile-layout-checklist.md","\u002Fblog\u002Fmobile-layout-checklist","做移动端页面适配时的检查笔记","从内容宽度、触控区域、文字换行和键盘焦点几个方面检查窄屏体验。","2026-08-20",5,[151,162,163],"响应式","可访问性",{"id":165,"path":166,"title":167,"description":168,"categorySlug":127,"categoryLabel":126,"publishedAt":169,"readingMinutes":135,"featured":132,"tags":170},"blog\u002Fblog\u002Freact-controlled-form.md","\u002Fblog\u002Freact-controlled-form","React 受控表单：从一个输入框开始","用一个简单的姓名输入框，理解 value、onChange 与 React state 之间的关系。","2026-09-18",[126,171,139],"表单",{"id":173,"path":174,"title":175,"description":176,"categorySlug":127,"categoryLabel":126,"publishedAt":177,"readingMinutes":104,"featured":130,"tags":178},"blog\u002Fblog\u002Freact-list-keys.md","\u002Fblog\u002Freact-list-keys","React 列表渲染里的 key 有什么用","通过稳定的 key 帮助 React 识别列表项目，避免用数组下标造成的状态错位。","2026-08-12",[126,179,139],"列表",{"id":181,"path":182,"title":183,"description":184,"categorySlug":127,"categoryLabel":126,"publishedAt":185,"readingMinutes":160,"featured":130,"tags":186},"blog\u002Fblog\u002Freact-props-and-state.md","\u002Fblog\u002Freact-props-and-state","React 组件里的 Props 和 State","用一个简单的信息卡片区分外部传入的数据和组件内部会变化的数据。","2026-08-28",[126,187,139],"组件",{"id":189,"path":190,"title":191,"description":192,"categorySlug":127,"categoryLabel":126,"publishedAt":193,"readingMinutes":160,"featured":130,"tags":194},"blog\u002Fblog\u002Freact-small-components.md","\u002Fblog\u002Freact-small-components","把重复的界面拆成小组件","从重复的按钮和卡片开始，认识组件拆分的几个简单信号。","2026-07-16",[126,187,195],"练习记录",{"id":4,"path":133,"title":5,"description":128,"categorySlug":127,"categoryLabel":126,"publishedAt":134,"readingMinutes":135,"featured":130,"tags":197},[126,15,139],{"id":199,"path":200,"title":201,"description":202,"categorySlug":127,"categoryLabel":126,"publishedAt":203,"readingMinutes":104,"featured":130,"tags":204},"blog\u002Fblog\u002Freact-use-state-practice.md","\u002Fblog\u002Freact-use-state-practice","用 useState 管理一个简单的计数交互","从加一和重置两个操作，熟悉 React state 的声明与更新方式。","2026-07-30",[126,205,195],"useState",{"id":207,"path":208,"title":209,"description":210,"categorySlug":211,"categoryLabel":212,"publishedAt":213,"readingMinutes":160,"featured":132,"tags":214},"blog\u002Fblog\u002Ftypescript-component-props.md","\u002Fblog\u002Ftypescript-component-props","给 React 组件的 Props 添加 TypeScript 类型","用必填属性和可选属性描述组件接口，让使用方式在编辑器里更清晰。","typescript","TypeScript","2026-09-02",[212,126,215],"类型",{"id":217,"path":218,"title":219,"description":220,"categorySlug":211,"categoryLabel":212,"publishedAt":221,"readingMinutes":160,"featured":132,"tags":222},"blog\u002Fblog\u002Ftypescript-narrowing.md","\u002Fblog\u002Ftypescript-narrowing","TypeScript 类型收窄入门","使用 typeof 和条件判断缩小联合类型的范围，让后续代码更安全。","2026-09-25",[212,223,139],"类型收窄",{"id":225,"path":226,"title":227,"description":228,"categorySlug":211,"categoryLabel":212,"publishedAt":229,"readingMinutes":104,"featured":130,"tags":230},"blog\u002Fblog\u002Ftypescript-union-status.md","\u002Fblog\u002Ftypescript-union-status","用联合类型描述请求状态","把加载、成功和失败等状态限制在明确的集合里，减少拼写错误和遗漏分支。","2026-08-04",[212,231,139],"联合类型",{"id":233,"path":234,"title":235,"description":236,"categorySlug":237,"categoryLabel":238,"publishedAt":239,"readingMinutes":104,"featured":130,"tags":240},"blog\u002Fblog\u002Fvite-react-project.md","\u002Fblog\u002Fvite-react-project","用 Vite 创建一个 React + TypeScript 小项目","记录从初始化模板到启动开发服务器的基础步骤，以及几个值得先检查的文件。","tools","开发工具","2026-06-12",[241,126,212],"Vite",1792674168658]