在上下文中反应悬念

问题描述 投票:0回答:1

那些天我必须解决我的 React 应用程序的问题,我所有的数据都以 JSON 形式显示,这些数据由使用节点 FS 的 express API 提供服务,以便读取这些 JSON 并根据你正在经过的路径。

真正的问题出现在我尝试渲染我的组件时,如果没有 JSON 信息,组件将毫无用处,所以我必须一直等到获得这些信息。

我的第一个想法是使用 XMLHttpRequest

 同步调用 API,但我在文档中看到它已
已弃用。因此,我阅读了Suspense 和 Transitions 的新功能,但我不理解它以及将它们放入我的 DataContext 中。我将与您分享我认为相关的所有代码,以便让您了解我达到的目标:

// jsonLoader.js // Here I try to get the data with XMLHttpRequest, I replaced to sync to async export const loadJSON = async (path) => { const json = await readFile(path, 'application/json'); return json ? JSON.parse(json) : undefined; }; const readFile = async (path, mimeType) => new Promise((resolve) => { const xmlHttp = new XMLHttpRequest(); xmlHttp.open('GET', path, true); if (!!mimeType && xmlHttp.overrideMimeType) xmlHttp.overrideMimeType(mimeType); xmlHttp.send(); if (xmlHttp.status == 200 && xmlHttp.readyState == 4) resolve(xmlHttp.responseText); else return resolve(undefined); });
然后我在 DataContext 中使用该模块:

// DataContext.js // I'm trying to serve a "useQuery" called "getData" in order to fetch the API let data = {}; const index = (obj, path) => path.split('.').reduce((o, i) => o[i], obj); const setter = (obj, path, value) => { if (typeof path == 'string') return setter(obj, path.split('.'), value); else if (path.length == 1 && value !== undefined) return (obj[path[0]] = value); else if (path.length == 0) return obj; else return setter(obj[path[0]], path.slice(1), value); }; const DataContextInstance = createContext({ getData: async (...paths) => ({}), getTranslations: () => ({}), }); export const DataContext = ({dataLoaded, children}) => { if (dataLoaded) data = dataLoaded; const {lang} = useContext(UserContext); const [prevLang, setPrevLang] = useState(); const loadData = (path) => { if (Object.keys(data).length > 0) { const foundData = index(data, path); if (foundData?.then) throw foundData; if (foundData) return data; } const filePath = `/data/${path || `translations/${lang}`}.json`; const json = loadJSON(filePath).then((newData) => (data[path] = newData)); data[path] = json; }; const getData = (...paths) => { if (paths.every((p) => index(data, p))) return data; paths.forEach((p) => loadData(p)); return data; }; useEffect(() => { if (lang === prevLang && Object.keys(data).length > 0) return; if (Object.keys(data).length > 0) return; loadData(); setPrevLang(lang); }, [lang, prevLang, setPrevLang, data]); const contextValue = useMemo( () => ({getData, getTranslations: () => getData()}), [data, lang] ); return ( <DataContextInstance.Provider value={contextValue}> <Suspense fallback={<span>Loading...</span>}>{children}</Suspense> </DataContextInstance.Provider> ); }; export const useDataContext = () => { const context = useContext(DataContextInstance); if (!context) throw new Error('Context must be used within a Provider'); return context; };
然后,我在组件中使用“getData”来获取该组件所需的数据:

// NavBar.js // Here I use my hook to get the DataContext context and get the "getData" func function NavBar() { const {getData} = useDataContext(); const {pages} = getData('menu').menu; [...]

如您所见,我在每个组件中指定了我想要的 json,以避免加载所有组件,因此
我在 DataContext 中将“data”变量作为“缓存”,所以如果加载了它,我只需退货即可

我的问题是我无法完成这项工作,它会陷入调用循环并且永远不会悬念(我认为)。 编辑

:我设法捕获错误日志:

Warning: Cannot update a component (`DataContext`) while rendering a different component (`AppBase`). To locate the bad setState() call inside `AppBase`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render

JSX结构是:

<DataContext dataLoaded={data}> <AppBase data={data} statusCode={statusCode} /> </DataContext>
    

我通过添加以下几行解决了这个问题,在添加
data[path] = json
(插入承诺)之后,我必须
javascript reactjs node.js xmlhttprequest
1个回答
1
投票
以告诉React它正在加载承诺:

[...]
const filePath = `/data/${path || `translations/${lang}`}.json`;
if (!path) path = lang;
const json = loadJSON(filePath).then((newData) => (data[path] = newData));
data[path] = json;
if (data[path]?.then) throw data[path];
[...]
我按照 CSS Tricks

中的说明进行操作。
谢谢大家的帮助!

© www.soinside.com 2019 - 2024. All rights reserved.