React TypeScript Context Provider同步读取JSON文件及报错解决
核心问题
你的现有实现存在两个本质错误,和TS类型报错无关:
node-sync是Node.js服务端专属库,依赖Node.js底层的协程能力实现,浏览器环境完全不兼容,无法在前端React项目中运行- ES动态
import()语法本身是异步API,返回Promise对象,即使套一层Sync包裹,也无法在浏览器环境中转为同步执行逻辑。TS报错的本质是类型系统无法识别你在Sync回调中对data变量的赋值,初始声明的let data没有指定类型,TS推导其类型为undefined,加可选链后进一步被收窄为never类型,自然无法识别find方法。
可行同步读取方案
对于前端React+TS项目,要同步读取体积极小的本地JSON文件,不需要引入任何第三方库,直接使用构建工具原生支持的静态import导入JSON即可,导入的值是构建时就打包进bundle的同步常量,完全不需要处理加载状态。
改造后的完整实现代码如下:
import React, { createContext, useContext, Consumer, Context, ReactNode, useMemo, } from 'react'; // 静态导入本地JSON文件,Webpack/Vite/CRA等所有常见React构建工具原生支持 import mainData from '../main.json'; import testData from '../test.json'; export interface DataProviderProps { children: ReactNode; } export interface Data { secretNumber?: string; } interface JsonItem { name: string; secretNumber?: string; } // 传入默认值初始化Context,不需要额外加@ts-ignore忽略类型 const DataContext: Context<Data> = createContext<Data>({ secretNumber: undefined }); export function DataProvider({ children }: DataProviderProps) { const secretNumber = useMemo(() => { // 根据环境变量直接选择预导入的JSON数据,纯内存读取,完全同步 const data: JsonItem[] = process.env.REACT_APP_WORLD === 'main' ? mainData : testData; return data.find(({ name }) => name === 'elonmusk')?.secretNumber; }, []); const states = useMemo<Data>(() => ({ secretNumber }), [secretNumber]); return ( <DataContext.Provider value={states}> {children} </DataContext.Provider> ); } export function useData(): Data { return useContext(DataContext); } export const DataConsumer: Consumer<Data> = DataContext.Consumer;
注意事项
- 如果TS提示无法识别JSON模块导入,在项目全局类型声明文件(CRA项目为
react-app-env.d.ts,Vite项目为vite-env.d.ts)中添加以下声明即可:
declare module '*.json' { const value: Record<string, any> | any[]; export default value; }
- 浏览器环境本身没有提供同步读取本地外部文件的API,所有声称实现同步IO的前端库本质都是靠构建时预打包、或者XHR同步请求实现,后者会阻塞主线程严重影响性能,不推荐使用。静态导入的方案是构建时把JSON内容直接打入JS包,运行时无额外请求,性能最优,完全匹配小体积JSON的使用场景。
内容的提问来源于stack exchange,提问作者gameveloster
相关产品推荐
相关产品推荐

