api获取请求失败后重新调用useEffect
Posted
技术标签:
【中文标题】api获取请求失败后重新调用useEffect【英文标题】:Re-calling useEffect after a failed api fetching request 【发布时间】:2020-07-07 10:02:27 【问题描述】:我正在执行 useEffect() 以使用 JSON 数据更新状态。但是获取请求有时会失败,所以如果发生这种情况,我想重新执行 useEffect 钩子:
...
import React, useState, useEffect from 'react';
import getJsonData from './getJsonData';
const myApp = () =>
var ErrorFetchedChecker = false;
const [isLoading,setIsLoading] = useState(true);
const [data,setData] = useState(null);
const updateState = jsonData =>
setIsloading(false);
setData(jsonData);
;
useEffect(() =>
//console.log('EXECUTING');
getJsonData().then(
data => updateState(data),
error =>
Alert.alert('DATA FETCHING ERROR !', 'Refreshing ?...');
ErrorFetchedChecker = !ErrorFetchedChecker;
//console.log('LOG__FROM_CountriesTable: Executed');
,
);
, [ErrorFetchedChecker]);//Shouldn't the change on this variable
//be enough to re-execute the hook ?
return (
<View>
<Text>state.data.title</Text>
<Text>data.data.completed</Text>
</View>
);
这是 getJsonData() 函数以防万一:
export async function getJsonData()
try
let response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let responseJson = await response.json();
return responseJson;
catch (error)
throw error;
// Also, is this the correct way to handle the error ?
// As the Alert in useEffect goes off either ways.
// If not, advise me on how the error should be handled.
【问题讨论】:
useEffect 会在你的反应状态改变时再次运行,如果你的局部变量改变它不会再次运行。将 ErrorFetchedChecker 转换为反应状态。 props 也会导致重新渲染,因此 useEffect 将在 prop 更改时再次运行 确实如此,但是这里 ErrorFetchedChecker 的生命周期非常短,因为 react 不会在其堆栈中存储其他变量值。这就是使用 useState 的原因。 【参考方案1】:import React, useState, useRef, useEffect from "react";
import Text, View, TextInput from "react-native";
const App = () =>
var ErrorFetchedChecker = false;
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState(null);
const updateState = (jsonData) =>
setIsLoading(false);
setData(jsonData);
;
useEffect(() =>
//console.log('EXECUTING');
getJsonData()
.then((data) =>
console.log("1. Successful, just received the data from our promise");
updateState(data);
console.log("2. We set our data because we received it successfully");
return alreadySet: true ;
)
.catch((e) =>
console.log("1. We failed to gather data in our initial promise");
console.log("2. Attempting to rerun initial promise");
return getJsonData();
)
.then((data) =>
if (data.alreadySet)
console.log(
"3. Did not attempt to retry because we are already successful"
);
else
console.log("3. Our second attempt succeeded");
updateState(data);
console.log("4. Set our data on our second attempt");
)
.catch((e) =>
console.log("3. Both attempts have failed");
);
, []); //Shouldn't the change on this variable
//be enough to re-execute the hook ?
return (
<View>
<Text>data ? <Text>data.title</Text> : null</Text>
</View>
);
;
export async function getJsonData()
try
let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
let responseJson = await response.json();
return responseJson;
catch (error)
throw error;
// Also, is this the correct way to handle the error ?
// As the Alert in useEffect goes off either ways.
// If not, advise me on how the error should be handled.
export default App;
【讨论】:
你的意思是用 [getJsonData()] 替换 [ErrorFetchedChecker] 吗?这样做时,我收到 2 个警告:“可能未处理的承诺拒绝”:1.TypeError: Network request failed 和 2.SyntaxError: JSON Parse Error unrecognized token 你能看看上面的截图吗?试着用我的手机哈哈....告诉我,如果这不起作用,我可以跳上我的电脑 还是不行,只执行一次 你发送的链接只有默认的react native View 等待您的更新,虽然我明白您所说的 x-times 的意思。好主意!【参考方案2】:这会起作用
const myApp = () =>
const [errorFetchedChecker, setErrorFetchedChecker] = useState(false);
const [isLoading,setIsLoading] = useState(true);
const [data,setData] = useState(null);
const updateState = jsonData =>
setIsloading(false);
setData(jsonData);
;
useEffect(() =>
//console.log('EXECUTING');
getJsonData().then(
data => updateState(data),
error =>
Alert.alert('DATA FETCHING ERROR !', 'Refreshing ?...');
setErrorFetchedChecker(c => !c);
//console.log('LOG__FROM_CountriesTable: Executed');
,
);
, [errorFetchedChecker]);
return (
<View>
<Text>state.data.title</Text>
<Text>data.data.completed</Text>
</View>
);
【讨论】:
谢谢,一个很好的解决方案。我可以在执行时添加超时吗?例如,useEffect 每 2 秒重新执行一次,因为它使应用程序有点滞后。 是的,您可以在 useEffect 中设置超时,但不要忘记 clearTimeout。 ***.com/questions/53090432/… 这对我也很有效——做得非常好。问题: (c => !c) 究竟在做什么?我知道结果是将 errorFetchedChecker 的状态从 false 更改为 true,但我之前没有在 useState 挂钩中看到过这种模式,也没有在其他地方引用过“c”。此外,为什么即使重复尝试也能奏效——直觉上我认为多次调用(在多次失败的情况下)会来回切换错误状态,但这似乎不是正在发生的事情。 @ChrisPerry 代码将箭头函数传递给setErrorFetchedChecker
。基本上,您可以传递一个将当前值作为第一个参数并返回新值的函数。在这里,它被用来切换errorFetchedChecker
值。你可以read more in the docs。以上是关于api获取请求失败后重新调用useEffect的主要内容,如果未能解决你的问题,请参考以下文章
函数失败后我是不是应该重新调用 API 函数并在 c# 中刷新我的访问令牌?
如何设计API接口,请求接口时需要进行身份验证,防止第三方随意调用接口?
使用 fetch api 调用带有 keepalive 的 POST 请求时,预检请求失败