Next.js SSR函数组件中Set State类型收窄问题(无需类型断言)
无需类型断言实现React useState Dispatch类型收窄
问题场景
现有一个接收Next.js SSR传递props的React函数组件,初始代码如下:
const Component = ({ err, n }: { err?: ErrorType; n?: N }) => { const [x, setX] = useState(n || null) // ...其他逻辑 if(err){ return <ErrorComponent err={err} /> } else if(!(x===null)){ return <SomeComponent setX={setX} /> } }
这里x的类型为N | null,通过条件判断可将其类型收窄为N,但setX的类型仍为Dispatch<SetStateAction<N | null>>,而SomeComponent要求传入的setX类型为Dispatch<SetStateAction<N>>。
尝试将useState放在条件判断后虽能解决类型问题,但违反了React Hook调用规则,抛出错误:React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.
解决方案
方案1:包装符合类型要求的setter函数
在x类型已收窄的分支中,包装一个只接受N类型更新的函数,TypeScript会自动推导其类型为Dispatch<SetStateAction<N>>,无需断言:
const Component = ({ err, n }: { err?: ErrorType; n?: N }) => { const [x, setX] = useState(n || null); if (err) { return <ErrorComponent err={err} />; } if (x !== null) { // 包装出符合SomeComponent要求的setter const setXForComponent = (value: SetStateAction<N>) => { setX(value); }; return <SomeComponent setX={setXForComponent} />; } // 处理x为null的边界情况,比如返回加载组件 return <LoadingComponent />; };
方案2:拆分组件分离校验与渲染逻辑
将props校验、错误处理与核心渲染逻辑拆分为两个组件,外层组件负责过滤无效props,内层组件只接收确定类型的参数,确保useState的类型正确:
// 内层组件:仅接收确定类型的初始值 const ComponentContent = ({ initialN }: { initialN: N }) => { const [x, setX] = useState(initialN); return <SomeComponent setX={setX} />; }; // 外层组件:处理错误与props校验 const Component = ({ err, n }: { err?: ErrorType; n?: N }) => { if (err || n == null) { return <ErrorComponent err={err} />; } return <ComponentContent initialN={n} />; };
内容的提问来源于stack exchange,提问作者Lucien950
相关产品推荐
相关产品推荐

