如何修复TypeScript报错:Context Provider的value数组每次渲染变化
React Context Provider 类型错误与性能警告解决方法
问题场景
我编写了以下React Context与Provider代码:
const SearchParamsStateProvider = ({ children, }: { children: React.ReactNode; }) => { const [searchParams, setSearchParams] = useSearchParams(); return ( <SearchParamsStateContext.Provider value={[searchParams, setSearchParams]}> {children} </SearchParamsStateContext.Provider> ); }; const SearchParamsStateContext = createContext< [searchParams: URLSearchParams, setSearchParams: SetURLSearchParams] >([ new URLSearchParams(''), ( search?: | URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit), ) => search, ]);
TypeScript在value={[searchParams, setSearchParams]}行抛出性能警告:
The array passed as the value prop to the Context provider (at line
12) changes every render. To fix this consider wrapping it in a
useMemo hook.
尝试用useMemo优化后:
const value = useMemo( () => [searchParams, setSearchParams], [searchParams, setSearchParams], ); return ( <SearchParamsStateContext.Provider value={value}> {children} </SearchParamsStateContext.Provider> );
又出现类型错误:
Type '(URLSearchParams | SetURLSearchParams)[]' is not assignable to type '[searchParams: URLSearchParams, setSearchParams: SetURLSearchParams]'. Target requires 2 element(s) but source may have fewer.
解决方案
方法1:显式断言元组类型
TypeScript默认会把[searchParams, setSearchParams]推断为联合类型数组,而非严格元组。可以通过类型断言强制指定为定义好的元组类型:
const value = useMemo( () => [searchParams, setSearchParams] as [URLSearchParams, SetURLSearchParams], [searchParams, setSearchParams], );
或者复用Context的默认值类型,避免重复编写类型:
const value = useMemo( () => [searchParams, setSearchParams] as typeof SearchParamsStateContext.defaultValue, [searchParams, setSearchParams], );
方法2:改用对象传递上下文
元组的类型推断容易出现歧义,换成对象结构可以让TypeScript更清晰识别类型,同时提升上下文使用的可读性:
首先修改Context定义:
const SearchParamsStateContext = createContext<{ searchParams: URLSearchParams; setSearchParams: SetURLSearchParams; }>({ searchParams: new URLSearchParams(''), setSearchParams: (search?: URLSearchParamsInit | ((prev: URLSearchParams) => URLSearchParamsInit)) => search, });
然后在Provider中使用对象:
const value = useMemo( () => ({ searchParams, setSearchParams }), [searchParams, setSearchParams], ); return ( <SearchParamsStateContext.Provider value={value}> {children} </SearchParamsStateContext.Provider> );
方法3:指定useMemo的泛型参数
直接给useMemo指定泛型,明确它返回的是严格元组类型:
const value = useMemo<[URLSearchParams, SetURLSearchParams]>( () => [searchParams, setSearchParams], [searchParams, setSearchParams], );
以上三种方法都能解决类型错误,同时消除性能警告。如果追求代码可读性,推荐使用方法2;如果想保留元组结构,方法1或3均可。
内容的提问来源于stack exchange,提问作者Croviajo
相关产品推荐
相关产品推荐

