React如何等待useEffect执行完成再渲染UI,能否使用Suspense?
问题根因
你当前写的组件混用了函数组件和类组件的语法,且默认会在任何状态下直接渲染input,当父组件的passedData还没完成服务端请求时,本地状态初始为undefined,渲染阶段直接执行getAutofocus()就会出现不符合预期的结果。
最优实现方案
最轻量化且兼容性最好的方案是加加载态条件渲染,不需要修改上层父组件逻辑,仅调整当前组件即可:
- 先修正组件的语法错误:函数组件不需要
render方法,也不能用this绑定ref - 新增加载判断逻辑,当数据未完成初始化时,返回加载占位UI,不渲染输入框
- 可以直接省略冗余的本地状态同步逻辑,直接用props传入的
passedData做判断,减少不必要的重渲染
修正后的代码如下:
interface MyValue { //interface declaration } // 函数组件接收props参数 export function MyComponent({ passedData }: { passedData?: MyValue }) { const inputRef = useRef<HTMLInputElement>(null); function getAutofocus() { // 此时passedData一定存在,直接基于该值计算即可 // return true/false based on passedData value } // 加载态判断,数据没回来之前返回占位UI if (!passedData) { return <div>加载中...</div> // 也可以返回骨架屏、空节点,根据业务需求调整即可 } // 数据加载完成后才渲染输入框,此时调用getAutofocus一定是正常的 return ( <div> <input autoFocus={getAutofocus()} ref={inputRef} /> </div> ); }
能否使用React Suspense实现
可以使用,但需要上层数据获取逻辑适配Suspense规范:
- 如果你父组件的GET请求是通过支持Suspense的方案(比如React Query、SWR、Next.js App Router的服务端组件数据获取)实现的,直接把当前组件包裹在
<Suspense fallback={<div>加载中...</div>}>里即可,Suspense会自动等待数据加载完成后再渲染MyComponent,不需要在当前组件内加任何判断逻辑。 - 如果你的项目没有用支持Suspense的数据流方案,自己实现符合Suspense规范的异步读取逻辑成本远高于上面的条件渲染方案,这种情况不推荐用Suspense。
内容的提问来源于stack exchange,提问作者Sanath
相关产品推荐
相关产品推荐

