如何使用反应路由器基于状态导航
How to navigate based on state using react router
在我的 React 项目中,我使用 fetch api 从后端获取用户配置文件。如果 API 调用中出现任何错误,我会在屏幕上显示它。
const navigate = useNavigate();
const [errorMessage, setErrorMessage] = React.useState("");
...
const handleGetProfile = async () => {
await fetch(`${API_URL}/profile`).then(...).catch(err=>setErrorMessage(err.message))
!errorMessage && navigate("/");
}
只有在 api 调用中 没有错误 时,我才想导航到根路径。所以我正在检查错误是否为空并导航到根路径。
这种方法的问题是 setErrorMessage
不能保证立即更新,因为它会安排状态更新,所以它总是导航到根路径,即使出现错误也是如此。
我该如何解决这个问题,有什么建议吗?
正确,因为 React 状态更新是异步处理的,并被视为 const
errorMessage
状态不会在 handleGetProfile
回调中更新。
const handleGetProfile = async () => {
await fetch(`${API_URL}/profile`)
.then(...)
.catch(err => setErrorMessage(err.message));
!errorMessage && navigate("/");
}
将 async/await
与 Promise 链混合使用也是 anti-pattern。通常你使用其中之一。
要解决,您应该将 navigate
调用 移动到 逻辑的“已解决”部分。由于 fetch
returns Promise 和 only reject on network errors 你还需要检查响应状态。
见Checking that the fetch was successful
A fetch() promise will reject with a TypeError when a
network error is encountered or CORS is misconfigured on the
server-side, although this usually means permission issues or similar
— a 404 does not constitute a network error, for example. An accurate
check for a successful fetch()
would include checking that the
promise resolved, then checking that the Response.ok property has
a value of true. The code would look something like this:
fetch('flowers.jpg')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not OK');
}
return response.blob();
})
.then(myBlob => {
myImage.src = URL.createObjectURL(myBlob);
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
使用 Promise 链
const handleGetProfile = () => {
fetch(`${API_URL}/profile`)
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not OK');
}
// handle any successful response stuff
navigate("/");
})
.catch(err => {
setErrorMessage(err.message || err);
});
}
将 async/await
与 try/catch
结合使用
const handleGetProfile = async () => {
try {
const response = await fetch(`${API_URL}/profile`);
if (!response.ok) {
throw new Error('Network response was not OK');
}
// handle any successful response stuff
navigate("/");
} catch(err) {
setErrorMessage(err.message || err);
}
}
使用 useEffect
挂钩来响应状态变化
const navigate = useNavigate();
const [isFetched, setIsFetched] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState("");
useEffect(() => {
if (isFetched && !errorMessage) {
navigate("/");
}
}, [errorMessage, isFetched, navigate]);
...
const handleGetProfile = async () => {
setErrorMessage(null);
setIsFetched(false);
try {
const response = await fetch(`${API_URL}/profile`);
if (!response.ok) {
throw new Error('Network response was not OK');
}
// handle any successful response stuff
navigate("/");
} catch(err) {
setErrorMessage(err.message || err);
} finally {
setIsFetched(true);
}
}
在我的 React 项目中,我使用 fetch api 从后端获取用户配置文件。如果 API 调用中出现任何错误,我会在屏幕上显示它。
const navigate = useNavigate();
const [errorMessage, setErrorMessage] = React.useState("");
...
const handleGetProfile = async () => {
await fetch(`${API_URL}/profile`).then(...).catch(err=>setErrorMessage(err.message))
!errorMessage && navigate("/");
}
只有在 api 调用中 没有错误 时,我才想导航到根路径。所以我正在检查错误是否为空并导航到根路径。
这种方法的问题是 setErrorMessage
不能保证立即更新,因为它会安排状态更新,所以它总是导航到根路径,即使出现错误也是如此。
我该如何解决这个问题,有什么建议吗?
正确,因为 React 状态更新是异步处理的,并被视为 const
errorMessage
状态不会在 handleGetProfile
回调中更新。
const handleGetProfile = async () => {
await fetch(`${API_URL}/profile`)
.then(...)
.catch(err => setErrorMessage(err.message));
!errorMessage && navigate("/");
}
将 async/await
与 Promise 链混合使用也是 anti-pattern。通常你使用其中之一。
要解决,您应该将 navigate
调用 移动到 逻辑的“已解决”部分。由于 fetch
returns Promise 和 only reject on network errors 你还需要检查响应状态。
见Checking that the fetch was successful
A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server-side, although this usually means permission issues or similar — a 404 does not constitute a network error, for example. An accurate check for a successful
fetch()
would include checking that the promise resolved, then checking that the Response.ok property has a value of true. The code would look something like this:fetch('flowers.jpg') .then(response => { if (!response.ok) { throw new Error('Network response was not OK'); } return response.blob(); }) .then(myBlob => { myImage.src = URL.createObjectURL(myBlob); }) .catch(error => { console.error('There has been a problem with your fetch operation:', error); });
使用 Promise 链
const handleGetProfile = () => { fetch(`${API_URL}/profile`) .then((response) => { if (!response.ok) { throw new Error('Network response was not OK'); } // handle any successful response stuff navigate("/"); }) .catch(err => { setErrorMessage(err.message || err); }); }
将
结合使用async/await
与try/catch
const handleGetProfile = async () => { try { const response = await fetch(`${API_URL}/profile`); if (!response.ok) { throw new Error('Network response was not OK'); } // handle any successful response stuff navigate("/"); } catch(err) { setErrorMessage(err.message || err); } }
使用
useEffect
挂钩来响应状态变化const navigate = useNavigate(); const [isFetched, setIsFetched] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(""); useEffect(() => { if (isFetched && !errorMessage) { navigate("/"); } }, [errorMessage, isFetched, navigate]); ... const handleGetProfile = async () => { setErrorMessage(null); setIsFetched(false); try { const response = await fetch(`${API_URL}/profile`); if (!response.ok) { throw new Error('Network response was not OK'); } // handle any successful response stuff navigate("/"); } catch(err) { setErrorMessage(err.message || err); } finally { setIsFetched(true); } }