[英]React: How to hit API only once using useEffect
我在 API 调用中有一组对象,我是从useEffect
调用的。 基本上我想要的是,我只想打一次 API 并将数组设置在localStorage
中。
现在,如果 localStorage 有一些与之相关的数据,则使用useState
的集合数组将通过localStorage
在其中设置,否则如果它不包含任何与之相关的项目,那么它将再次访问 API 以获取数组并设置为localStorage
。
到目前为止我所做的代码是:
const [loadedg, setloadedg] = useState(false);
const [domainListGroupItems, setdomainListGroupItems] = useState([]);
useEffect(() => {
//---------->Groups Lists<----------------
if(!loadedg) {
setdomainListGroupItems(JSON.parse(localStorage.getItem('leftgroup')))
}else{
ApiService(leftgroups).then((response) => {
if (response.statusCode === 1) {
const item = response.domainGroupList
localStorage.setItem('leftgroup', JSON.stringify(item));
setloadedg(true);
console.log(item);
} else {
setloadedg(false);
}
})
.catch((error) => {
console.log(error)
})
}
}, [loadedg]);
我在这里使用的概念基本上是使用我认为应该使用的 boolean 条件。 但如果它可以在不使用 boolean 值的情况下完成,那对我来说会很棒。
我将如何解决这个问题? 谢谢你。
您可以使用值初始化 state
const [domainListGroupItems, setdomainListGroupItems] = useState(JSON.parse(localStorage.getItem('leftgroup')));
然后,在您的useEffect
中,只需检查domainListGroupItems
是否为 null
useEffect(() => {
if (domainListGroupItems) return; // already set from localStorage
ApiService(leftgroups).then((response) => { .... })
}, [domainListGroupItems]);
为了限制useEffect只触发一次,您可以从依赖数组中删除加载的g,现在它将简单地检查数据是否已经存在于本地存储中,如果没有,它将获取数据并将数据设置在本地存储中.
希望它能解决你的问题。
因此,您想使用 localStorage 作为客户端缓存,设置到期日期比检查密钥是否存在更有趣。 在下面的代码片段中,我将localStorage
填充为ls
并将 API 调用设置为带有setTimeout
的promise
用于测试目的。
我将 apiCall 效果提取为独立的,因此您可以在任何地方使用它,并给它一个skip
参数。 在代码段中,如果本地存储缓存的日期少于 7 天,则将跳过调用。 您可以编辑片段并取消注释 2 行以测试缓存是最近时会发生什么。 请务必将代码段扩展为“整页”,否则控制台日志会隐藏 localStorage 值:)
const useState = React.useState, useEffect = React.useEffect; // network call shim function ApiService() { return new Promise((resolve, reject) => { setTimeout(() => { try { resolve({ statusCode: 1, domainGroupList: ['Hello','World'] }); } catch (err) { reject(new Error('500 Server Error')); } }, 1000); }); } // localstorage shim const ls = Object.create({ getItem(key) { return this[key]; }, setItem(key, value) { this[key] = value; } }); // comment out to see what happens when ls has been populated less than 7d ago // ls.setItem('lastfetch', new Date().toISOString()); // ls.setItem('groupleft', []); function isLessThan7DaysAgo(date) { const today = new Date(); return date > new Date(today.setDate(today.getDate()-7)); } const apiCallEffect = (onLoad, skip) => () => { if (skip) return; ApiService().then((response) => { if (response.statusCode === 1) { const items = response.domainGroupList; ls.setItem('leftgroup', JSON.stringify(items)); ls.setItem('lastfetch', new Date().toISOString()); if (onLoad) onLoad(items); } }).catch((error) => { console.log(error.message) }); } const App = ({ initialItems, onLoad }) => { const skip = ls.getItem('lastfetch') && isLessThan7DaysAgo(new Date(ls.getItem('lastfetch'))); const [loaded, setloaded] = useState(skip); const [groupItems, setGroupItems] = useState(initialItems); console.log(skip? 'skipping fetch, getting from ls': 'doing fetch, storing in ls'); useEffect(apiCallEffect((items) => { setloaded(true); setGroupItems(items); }, skip), [groupItems]); return <div> { loaded? <ul>{groupItems.map(x => (<li>{x}</li>)) }</ul>: <div>Loading...</div> } <strong>In localstorage</strong><br/> <pre>{JSON.stringify(ls, null, 2)}</pre> </div>; }; const storedDomainListGroupItems = ls.getItem('leftgroup') || []; ReactDOM.render(<App initialItems={storedDomainListGroupItems}/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script> <strong>In app:</strong> <div id="app"></div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.