[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo":3,"knowledge-related-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo":410,"knowledge-series-\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo":435},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":15,"pinned":16,"draft":16,"body":17,"seo":406,"stem":407,"id":408,"extension":409},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fmemo","Memo、Callback 与 Ref","本文介绍 useRef、useMemo、useCallback、memo 及自定义 Hook。见 Effect。","技能小册",[12,13,14],"react","hooks","memo","2021-02-28",false,{"type":18,"value":19,"toc":399},"minimark",[20,24,48,52,68,121,124,128,178,203,209,213,220,240,246,250,257,309,317,320,323,395],[21,22,8],"h1",{"id":23},"memocallback-与-ref",[25,26,27,28,32,33,32,36,32,39,41,42,47],"p",{},"本文介绍 ",[29,30,31],"code",{},"useRef","、",[29,34,35],{},"useMemo",[29,37,38],{},"useCallback",[29,40,14],{}," 及自定义 Hook。见 ",[43,44,46],"a",{"href":45},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Feffect","Effect","。",[49,50,31],"h2",{"id":51},"useref",[25,53,54,55,59,60,63,64,67],{},"保存",[56,57,58],"strong",{},"跨渲染可变值","，修改 ",[29,61,62],{},".current"," ",[56,65,66],{},"不触发","重新渲染。",[69,70,75],"pre",{"className":71,"code":72,"language":73,"meta":74,"style":74},"language-tsx shiki shiki-themes material-theme-lighter github-light github-dark","const inputRef = useRef\u003CHTMLInputElement>(null);\n\nuseEffect(() => {\n  inputRef.current?.focus();\n}, []);\n\nreturn \u003Cinput ref={inputRef} \u002F>;\n","tsx","",[29,76,77,85,92,98,104,110,115],{"__ignoreMap":74},[78,79,82],"span",{"class":80,"line":81},"line",1,[78,83,84],{},"const inputRef = useRef\u003CHTMLInputElement>(null);\n",[78,86,88],{"class":80,"line":87},2,[78,89,91],{"emptyLinePlaceholder":90},true,"\n",[78,93,95],{"class":80,"line":94},3,[78,96,97],{},"useEffect(() => {\n",[78,99,101],{"class":80,"line":100},4,[78,102,103],{},"  inputRef.current?.focus();\n",[78,105,107],{"class":80,"line":106},5,[78,108,109],{},"}, []);\n",[78,111,113],{"class":80,"line":112},6,[78,114,91],{"emptyLinePlaceholder":90},[78,116,118],{"class":80,"line":117},7,[78,119,120],{},"return \u003Cinput ref={inputRef} \u002F>;\n",[25,122,123],{},"也用于保存定时器 id、上一次的 props、避免闭包陈旧等。",[49,125,127],{"id":126},"usememo-usecallback","useMemo \u002F useCallback",[129,130,131,144],"table",{},[132,133,134],"thead",{},[135,136,137,141],"tr",{},[138,139,140],"th",{},"Hook",[138,142,143],{},"作用",[145,146,147,161],"tbody",{},[135,148,149,155],{},[150,151,152],"td",{},[29,153,154],{},"useMemo(() => compute(a, b), [a, b])",[150,156,157,158],{},"缓存",[56,159,160],{},"计算结果",[135,162,163,168],{},[150,164,165],{},[29,166,167],{},"useCallback(fn, deps)",[150,169,157,170,173,174,177],{},[56,171,172],{},"函数引用","（等价于 ",[29,175,176],{},"useMemo(() => fn, deps)","）",[69,179,181],{"className":71,"code":180,"language":73,"meta":74,"style":74},"const sorted = useMemo(() => [...items].sort(compare), [items]);\nconst handleClick = useCallback(() => {\n  onSelect(id);\n}, [id, onSelect]);\n",[29,182,183,188,193,198],{"__ignoreMap":74},[78,184,185],{"class":80,"line":81},[78,186,187],{},"const sorted = useMemo(() => [...items].sort(compare), [items]);\n",[78,189,190],{"class":80,"line":87},[78,191,192],{},"const handleClick = useCallback(() => {\n",[78,194,195],{"class":80,"line":94},[78,196,197],{},"  onSelect(id);\n",[78,199,200],{"class":80,"line":100},[78,201,202],{},"}, [id, onSelect]);\n",[25,204,205,208],{},[56,206,207],{},"原则","：先保证正确性，仅在性能分析后、且子组件因引用变化导致多余渲染时再使用。过度使用增加复杂度。",[49,210,212],{"id":211},"reactmemo","React.memo",[25,214,215,216,219],{},"对组件进行",[56,217,218],{},"浅比较 props","，props 未变则跳过重新渲染：",[69,221,223],{"className":71,"code":222,"language":73,"meta":74,"style":74},"const Row = memo(function Row({ item }: { item: Item }) {\n  return \u003Cli>{item.name}\u003C\u002Fli>;\n});\n",[29,224,225,230,235],{"__ignoreMap":74},[78,226,227],{"class":80,"line":81},[78,228,229],{},"const Row = memo(function Row({ item }: { item: Item }) {\n",[78,231,232],{"class":80,"line":87},[78,233,234],{},"  return \u003Cli>{item.name}\u003C\u002Fli>;\n",[78,236,237],{"class":80,"line":94},[78,238,239],{},"});\n",[25,241,242,243,245],{},"需配合稳定的 props（如 ",[29,244,38],{}," 传递的函数）才有效。",[49,247,249],{"id":248},"自定义-hook","自定义 Hook",[25,251,252,253,256],{},"以 ",[29,254,255],{},"use"," 开头的函数，内部可调用其他 Hooks，用于复用逻辑：",[69,258,260],{"className":71,"code":259,"language":73,"meta":74,"style":74},"function useWindowWidth() {\n  const [width, setWidth] = useState(window.innerWidth);\n  useEffect(() => {\n    const onResize = () => setWidth(window.innerWidth);\n    window.addEventListener(\"resize\", onResize);\n    return () => window.removeEventListener(\"resize\", onResize);\n  }, []);\n  return width;\n}\n",[29,261,262,267,272,277,282,287,292,297,303],{"__ignoreMap":74},[78,263,264],{"class":80,"line":81},[78,265,266],{},"function useWindowWidth() {\n",[78,268,269],{"class":80,"line":87},[78,270,271],{},"  const [width, setWidth] = useState(window.innerWidth);\n",[78,273,274],{"class":80,"line":94},[78,275,276],{},"  useEffect(() => {\n",[78,278,279],{"class":80,"line":100},[78,280,281],{},"    const onResize = () => setWidth(window.innerWidth);\n",[78,283,284],{"class":80,"line":106},[78,285,286],{},"    window.addEventListener(\"resize\", onResize);\n",[78,288,289],{"class":80,"line":112},[78,290,291],{},"    return () => window.removeEventListener(\"resize\", onResize);\n",[78,293,294],{"class":80,"line":117},[78,295,296],{},"  }, []);\n",[78,298,300],{"class":80,"line":299},8,[78,301,302],{},"  return width;\n",[78,304,306],{"class":80,"line":305},9,[78,307,308],{},"}\n",[25,310,311,312,316],{},"一个自定义 Hook 对应一个逻辑关注点，与 ",[43,313,315],{"href":314},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Fvue\u002Fdesign","Vue Composables"," 思路类似。",[49,318,319],{"id":319},"参考文献",[25,321,322],{},"以下链接在编写时均可正常访问：",[129,324,325,335],{},[132,326,327],{},[135,328,329,332],{},[138,330,331],{},"资料",[138,333,334],{},"说明",[145,336,337,350,361,372,383],{},[135,338,339,347],{},[150,340,341],{},[43,342,346],{"href":343,"rel":344},"https:\u002F\u002Fzh-hans.react.dev\u002Freference\u002Freact\u002FuseRef",[345],"nofollow","React：useRef",[150,348,349],{},"API",[135,351,352,359],{},[150,353,354],{},[43,355,358],{"href":356,"rel":357},"https:\u002F\u002Fzh-hans.react.dev\u002Freference\u002Freact\u002FuseMemo",[345],"React：useMemo",[150,360,349],{},[135,362,363,370],{},[150,364,365],{},[43,366,369],{"href":367,"rel":368},"https:\u002F\u002Fzh-hans.react.dev\u002Freference\u002Freact\u002FuseCallback",[345],"React：useCallback",[150,371,349],{},[135,373,374,381],{},[150,375,376],{},[43,377,380],{"href":378,"rel":379},"https:\u002F\u002Fzh-hans.react.dev\u002Freference\u002Freact\u002Fmemo",[345],"React：memo",[150,382,349],{},[135,384,385,392],{},[150,386,387],{},[43,388,391],{"href":389,"rel":390},"https:\u002F\u002Fzh-hans.react.dev\u002Flearn\u002Freusing-logic-with-custom-hooks",[345],"React：自定义 Hook",[150,393,394],{},"复用逻辑",[396,397,398],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":74,"searchDepth":87,"depth":87,"links":400},[401,402,403,404,405],{"id":51,"depth":87,"text":31},{"id":126,"depth":87,"text":127},{"id":211,"depth":87,"text":212},{"id":248,"depth":87,"text":249},{"id":319,"depth":87,"text":319},{"title":8,"description":9},"knowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fhooks\u002Fmemo","knowledge\u002Fknowledge\u002Fbooklet\u002Fframe\u002FReact\u002Fhooks\u002Fmemo.md","md",{"items":411},[412,415,419,423,427,431],{"path":45,"title":413,"description":414,"category":10,"score":305},"Effect 与副作用","useEffect 用于在组件渲染后执行与外部系统同步的逻辑（请求、订阅、手动改 DOM 等）。涵盖基本用法、依赖数组、适用\u002F不适用场景、useLayoutEffect、最佳实践与常见坑。",{"path":416,"title":417,"description":418,"category":10,"score":305},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fcontext","Context","Context 在组件树中跨层级传递数据，避免 props 逐层透传。涵盖创建与使用、自定义 Hook 封装、性能拆分、与全局状态库对照、最佳实践与常见坑。",{"path":420,"title":421,"description":422,"category":10,"score":305},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fhooks\u002Fstate","State 与 Reducer","Hooks 让函数组件拥有 state 与副作用能力。本文介绍 useState 与 useReducer。见 React 基础。",{"path":424,"title":425,"description":426,"category":10,"score":100},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Frendering","渲染与协调","React 将组件渲染为虚拟 DOM 树，再协调（reconciliation）到浏览器 DOM。理解该过程有助于解释 key、memo 与性能优化。涵盖渲染流程、Fiber、startTransition、Suspense、最佳实践与常见坑。",{"path":428,"title":429,"description":430,"category":10,"score":100},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Fproject","工程化","新建 React 项目时，官方与社区主流工具为 Vite；全栈场景常用 Next.js。涵盖 Vite + React、Create React App 现状、Next.js、目录结构、环境变量、部署、最佳实践与常见坑。",{"path":432,"title":433,"description":434,"category":10,"score":100},"\u002Fknowledge\u002Fbooklet\u002Fframe\u002Freact\u002Ftypescript","TypeScript","React 官方推荐 TypeScript。类型主要落在 Props、事件、Ref 与 Hooks 返回值上。见 组件。",{"series":436,"title":13,"items":437,"index":87,"prev":445,"next":446},"booklet\u002Fframe\u002Freact\u002Fhooks",[438,440,442,443],{"path":416,"title":417,"date":439,"pinned":16},"2021-10-16",{"path":45,"title":413,"date":441,"pinned":16},"2024-10-11",{"path":7,"title":8,"date":15,"pinned":16},{"path":420,"title":421,"date":444,"pinned":16},"2021-02-21",{"path":45,"title":413,"date":441,"pinned":16},{"path":420,"title":421,"date":444,"pinned":16}]