javascript - 在反应中获取数据的最佳方法是什么?
问题描述
我目前使用 contentful 进行数据管理,所以这次不是常用的 axios/fetch 方法。
我正在使用 useContext 将数据共享给我的组件,并使用 useEffect 设置新数据的状态。你问什么问题?丑陋的语法。当我在第二次重新渲染中传递数据时,我无法立即访问数据,data[0][0]
它还不存在,因此会引发错误。这导致了这种令人作呕的语法:<h5>{data ? data[0].sys.contentType.sys.id : ""}</h5>
它可能“很好”,并且“有效”。但这对我来说绝对是残酷的。
应用程序.jsx
const App = () => {
const contentfulHook = useState(null);
useEffect((e) => {
client.getEntries().then((res) => contentfulHook[1](res.items));
/*
OR - same result
(async () => {
const data = await client.getEntries().then((res) => res.items);
contentfulHook[1](await data);
})();
*/
//Remove preloader when content is loaded
setTimeout(() => {
const preloader = document.getElementById("preloader");
preloader.style.opacity = 0;
preloader.addEventListener("transitionend", (e) => {
preloader.remove();
});
}, 0);
}, []);
console.log(contentfulHook[0]);
return (
<contentfulContext.Provider value={contentfulHook}>
<BrowserRouter>
<Global />
<Pages />
</BrowserRouter>
</contentfulContext.Provider>
);
};
render(<App />, document.getElementById("root"));
解决方案
I'd suggest two things on that matter:
- Encapsulate that request logic in a custom hook, so you can remove that code from your component.
- Use
data
,loading
anderror
pattern (as used by Apollo and probably other libraries).
The result would be something like:
const App = () => {
const { data, loading, error } = useRequest();
return (
<contentfulContext.Provider value={data}>
<BrowserRouter>
<Global />
<Pages />
</BrowserRouter>
</contentfulContext.Provider>
);
};
const useRequest = () => {
const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
useEffect(() => {
setLoading(true)
client.getEntries()
.then((res) => setData(res.items))
.catch((e) => setError(e))
.finally(() => {
removePreloader();
setLoading(false);
});
}, []);
return { data, loading, error };
}
const removePreloader = () => {
setTimeout(() => {
const preloader = document.getElementById("preloader");
preloader.style.opacity = 0;
preloader.addEventListener("transitionend", (e) => {
preloader.remove();
});
}, 0);
}
render(<App />, document.getElementById("root"));
Either way, you still need to check for the data before accessing the data
attributes when rendering. Even if it is on a top-level condition like:
const App = () => {
const { data, loading, error } = useRequest();
return (
<contentfulContext.Provider value={data}>
<BrowserRouter>
<Global />
<Pages />
{data && <h5>{data[0].sys.contentType}</h5>}
</BrowserRouter>
</contentfulContext.Provider>
);
};
推荐阅读
- javascript - Laravel - Jquery,Ajax - 将 Nullable 数据作为数组插入数据库中
- google-cloud-platform - 谁支付 BigQuery 中跨多个用户的数据集的查询费用?
- mysql - 在 phpmyadmin 的存储过程中设置变量
- java - W/audio_hw_generic:没有为 HAL 泛洪 logcat 提供足够的数据?
- linux - Docker 不应该将新文件写入原始目录
- ubuntu - 安装 ros-kinetic-desktop-full 后找不到“rxtools”
- jquery - 点击展开 JSON 数据
- c# - 等待另一个任务的异步任务
- javascript - 纯 html+css+js 中的 CSS 设置与 Node.JS 中的不同
- r - 在频率表中搜索特定单词