输入搜索内容时useList钩子重复执行的问题及解决方法
解决方案
1. 缓存useList中的计算结果
每次组件重渲染时,你的useList都会重复执行_.cloneDeep和filter操作,生成全新的list和otherMenus对象——这不仅是无意义的重复计算,还可能触发额外的组件重渲染。用useMemo缓存这些计算结果,只有当依赖的data变化时才重新计算:
import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import _ from 'lodash' export default function useList() { const { data } = useQuery(GET_LIST, { // 可选:关闭不必要的自动重请求,避免组件重渲染时触发重复请求 refetchOnWindowFocus: false, refetchOnMount: false, }) const list = useMemo(() => { // 如果data不会被直接修改,可移除_.cloneDeep提升性能 return _.cloneDeep(data)?.menuTree?.filter(i => i.parentId === null) || [] }, [data]) const otherMenus = useMemo(() => { return data?.menuTree || [] }, [data]) return { list, otherMenus } }
2. 隔离输入框的重渲染范围
把输入框封装成用memo包裹的独立组件,这样只有当searchValue变化时,该组件才会重渲染,不会影响到使用useList的部分:
import { memo, useState } from 'react' import { Input } from 'antd' const SearchInput = memo(({ value, onChange }) => { return ( <Input value={value} className="shadow-none" onChange={e => onChange(e.target.value)} /> ) }) // 父组件中使用 const ParentComponent = () => { const [searchValue, setSearchValue] = useState('') const { list } = useList() return ( <div> <SearchInput value={searchValue} onChange={setSearchValue} /> {/* 渲染list相关内容 */} </div> ) }
3. 移除不必要的深拷贝
如果useQuery返回的data是只读状态(不会在组件内被修改),可以直接去掉_.cloneDeep,直接对data.menuTree做过滤——深拷贝是耗时操作,能省则省:
const list = useMemo(() => { return data?.menuTree?.filter(i => i.parentId === null) || [] }, [data])
内容的提问来源于stack exchange,提问作者Mir Stephen
相关产品推荐
相关产品推荐

