[英]my states are empty arrays in the first render, blank page after login
在我在 Android 上运行的 React Ionic 项目中,我希望能够登录并检查我作为用户是否同意我们的使用条款。 为此,我编写了以下函数,其中包括:
'/login'
API 端点(第一个请求)'/terms-of-use'
端点的 GET 请求'/accepted-terms-of-use'
端点的 GET 请求,使用标头中第一个请求的response.data.token
中的令牌'/terms-of-use'
与'/accepted-terms-of-use'
并在“TermsOfUse.tsx”中呈现用户通过missingTermsofUse
数组仍未接受的missingTermsofUse
。 如果missingTermsofUse
数组的长度为0
,则表示用户已经接受了所有使用条款,我们将他推送到homePage
,否则我们将他推送到TermsOfUse
页面。
我正在使用 Context 以便在应用程序的任何地方使用道具
登录.tsx
const history = useHistory();
const {
termsofUse,
setTermsofUse,
acceptedTermsofUse,
setAcceptedTermsofUse,
missingTermsofUse,
setMissingTermsofUse
} = React.useContext(MyContext);
const doLogin = async (e: any) => {
e.preventDefault();
const loginData = {
email: email,
password: password,
};
// plugin: https://github.com/capacitor-community/http
const options = {
url: "https://xxx/login",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
data: loginData,
};
await Http.request({
...options,
method: "POST",
})
.then((response: any) => {
if (response.status == 201) {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
const options1 = {
url: "https://xxx/terms-of-use",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
};
const options2 = {
url: "https://xxx/accepted-terms-of-use",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Token: response.data.token,
},
};
Http.request({ ...options1, method: "GET" }).then(
(response1: any) => {
setTermsofUse(response1.data);
Http.request({ ...options2, method: "GET" }).then(
(response2: any) => {
setAcceptedTermsofUse(response2.data);
//find terms of use which user has not accepted (entries which are present in response1 but not present in response2)
setMissingTermsofUse(
termsofUse.filter(
({
id,
name,
}: {
id: number;
name: number;
}) =>
!acceptedTermsofUse.find(
(entry: any) =>
entry.id == id && entry.name == name
)
)
);
}
);
}
);
}
missingTermsofUse.length != 0 ? history.push("/termsOfUse") : history.push("/homePage");
}
.catch((error) => {
console.log("Error:" + JSON.stringify(error));
});
};
登录后,我得到一个空白页,既不TermsofUse
页,也没有homePage
。 你知道什么可能导致错误吗? 我认为第一个渲染包含null
值,但我真的不知道如何重新编写请求以避免这种情况(如果这是导致问题的原因)。
我是 React 的新手,任何帮助将不胜感激。
编辑:
从日志中,我可以看到termsofUse
、 acceptedTermsofUse
和missingTermsofUse
是空的。 这意味着在登录期间,它们在 Context.tsx 中设置的初始值被呈现。 我该如何解决这个问题?
我对 React 不是很了解,但我发现了一些与如何处理异步代码相关的潜在问题:
await Http.request({
...options,
method: "POST",
})
.then((response: any) => {
...
我建议只坚持一种处理承诺的方法。 您可以在 google 上找到有关 async/await 与 then/catch 的大量信息,这是我认为已经很好解释的结果之一(不是我的): https : //medium.com/@dio.hamidou/async-await- vs-then-catch-4f64d42e6392
acceptedTermsofUse.length != 0 ? history.push("/termsOfUse") : history.push("/homePage");
将在您从 GET '/terms-of-use' 和 '/accepted-terms-of-use' 得到答案之前执行,因为它不在最内部的 .then() 中。 这可能是您得到空的missingTermsofUse的原因
希望这有助于进一步调试您的问题!
在承诺链的深处,您调用setMissingTermsofUse
。 如果我理解正确,该调用似乎假定termsofUse
的值已更新(由于之前调用setTermsofUse
)。 但是,在 React 中,对 set state 的调用是异步的,因此您的代码不能依赖它们立即发生。 我的猜测是您的doLogin
函数正在关闭termsOfUse
的陈旧值(可能是您将其初始化为空数组)——然后过滤该空数组,这自然只会给您一个空数组。
我认为您要么需要移动负责找出效果中“缺少使用条款”的逻辑(使用useEffect
React 钩子),然后只有在更新termsofUse
和acceptedTermsofUse
termsofUse
时才激活效果。 effect 中的代码可以访问更新后的值(因为 React 在状态发生变化后运行 effect)。
或者,你已经进入了新的价值termsofUse
和acceptedTermsofUse
你的内doLogin
功能(来自请求您寄出)。 所以也许只是直接使用这些响应的数据来找出缺少的使用条款。
未经测试,但类似于:
const doLogin = async (e: any) => {
e.preventDefault();
const loginData = {
dateOfBirth: birthday,
postalCode: postalCode,
};
// plugin: https://github.com/capacitor-community/http
const loginResponse = await Http.request({
url: "https://xxx/login",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
data: loginData,
method: "POST",
});
if (201 !== loginResponse.status || !loginResponse.data.token) {
return console.log(
"Response status indicates resource may not have been created or no token was included in response.",
{ response: loginResponse }
);
}
localStorage.setItem("user", JSON.stringify(loginResponse.data));
const token = loginResponse.data.token;
const termsOfUseResponse = await Http.request({
url: "https://xxx/terms-of-use",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
method: "GET",
});
setTermsofUse(termsOfUseResponse.data);
const acceptedTermsOfUseResponse = await Http.request({
url: "https://xxx/accepted-terms-of-use",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Token: token,
},
});
setAcceptedTermsofUse(acceptedTermsOfUseResponse.data);
const missingTermsOfUse = termsOfUseResponse.data.filter(
({ id, name }: { id: number; name: number }) =>
!acceptedTermsOfUseResponse.data.some(
(entry: any) => entry.id == id && entry.name == name
)
);
setMissingTermsofUse(missingTermsOfUse);
missingTermsOfUse.length !== 0
? history.push("/termsOfUse")
: history.push("/homePage");
};
所做的主要更改是:
some
array 方法(而不是find
),因为您只对布尔值感兴趣。missingTermsOfUse
(你的代码是用acceptedTermsofUse
,这似乎与你的问题的这部分):如果missingTermsofUse数组的长度为0,则表示用户已经接受了所有使用条款,我们将他推送到homePage,否则我们将他推送到TermsOfUse 页面。
旁注:您似乎在使用 TypeScript。 如果是这样,通常建议避免使用any
,因为您选择退出 TypeScript 提供的主要好处和安全性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.