我最近开始做出反应,并在一个新的应用程序中使用它,使用 Msal auth。 我创建了一个上下文来更新用户信息并在我需要的任何地方使用它们。在我刷新页面之前,它一直运行良好。
问题是:我的对象包含所有信息,但是当我想显示一个值时,它是“未定义的”(即使它存在于对象中),直到在页面上进行重新渲染(打开菜单,更改带有路由器的页面,...)。这导致我需要显示这些值的地方都是空的,我需要在页面中制作一些东西来显示它们。这不是真正的用户友好...
我的 UserContext.js
import { useIsAuthenticated as isAuthenticated } from "@azure/msal-react";
import { createContext, useState, useEffect } from "react";
import { useMsal } from "@azure/msal-react";
import { msalConfig } from "../authConfig";
const initUser = () => ({
ADuserdatas : {
homeAccountId : "",
accountEnabled : "",
companyName : "",
createdDateTime : "",
department : "",
displayName : "",
givenName : "",
id : "",
jobTitle : "",
mail : "",
mobilePhone : "",
officeLocation : "",
surname : "",
userType : "",
},
language : "en"
})
const UserDatasFromMS = ({ instance, accounts }) => {
let ADuserdatas = {};
const callMsGraph = (token) => {
[...]
}
const handleUser = () => {
instance
.acquireTokenSilent({
scopes: ["openid", "profile", "user.read"],
account: accounts[0],
authority: `https://login.microsoftonline.com/${msalConfig.auth.tenantId}`,
})
.then((response) => {
callMsGraph(response.accessToken).then((data) => {
ADuserdatas.homeAccountId = response.account.homeAccountId;
ADuserdatas.accountEnabled = data.accountEnabled;
ADuserdatas.companyName = data.companyName;
ADuserdatas.createdDateTime = data.createdDateTime;
ADuserdatas.department = data.department;
ADuserdatas.displayName = data.displayName;
ADuserdatas.givenName = data.givenName;
ADuserdatas.id = data.id;
ADuserdatas.jobTitle = data.jobTitle;
ADuserdatas.mail = data.mail;
ADuserdatas.mobilePhone = data.mobilePhone;
ADuserdatas.officeLocation = data.officeLocation;
ADuserdatas.surname = data.surname;
ADuserdatas.userType = data.userType;
});
});
}
handleUser();
return {ADuserdatas}
};
export const UserContext = createContext({});
export const UserContextProvider = ({children}) => {
const { instance, accounts } = useMsal();
const [datasFromMS, setDatasFromMS] = useState({});
useEffect(() => {
setDatasFromMS(isAuthenticated ? UserDatasFromMS({instance, accounts}) : initUser.ADuserdatas)
}, [instance, accounts])
return(
<UserContext.Provider
value={{
datasFromMS,
setDatasFromMS,
}}
>{children}</UserContext.Provider>
)
}
这是控制台显示给我的内容在刷新之后和其他组件重新渲染之前:
与
console.log(datasFromMS)
:
{
"ADuserdatas": {
"homeAccountId": "Correct value",
"accountEnabled": true,
"companyName": "Correct value",
"createdDateTime": "Correct value",
"department": "IT",
"displayName": "Correct value",
"givenName": "Correct value",
"id": "Correct value",
"jobTitle": "Correct value",
"mail": "Correct value",
"mobilePhone": null,
"officeLocation": "Correct value",
"surname": "Correct value",
"userType": "Correct value"
}
}
与
console.log(datasFromMS?.ADuserdatas)
{
"homeAccountId": "Correct value",
"accountEnabled": true,
"companyName": "Correct value",
"createdDateTime": "Correct value",
"department": "IT",
"displayName": "Correct value",
"givenName": "Correct value",
"id": "Correct value",
"jobTitle": "Correct value",
"mail": "Correct value",
"mobilePhone": null,
"officeLocation": "Correct value",
"surname": "Correct value",
"userType": "Correct value"
}
与
console.log(datasFromMS?.ADuserdatas?.companyName)
undefined
几天来我一直在尝试解决这个问题,并尝试了很多可能性:导出 UserDatasFromMS()、数组、对象、createContext 中的值、状态中的 initUser、将上下文与 useUser 挂钩结合起来、在 App 中添加 useState( ), ... 太多的可能性,我无法一一列举。
提前感谢您的帮助!
这是对异步代码的误解。当您调用
UserDatasFromMS
时,一个 promise 就开始了。这意味着当该函数第一次返回时,ADuserdatas
甚至不会被设置,因为该函数在 promise 异步解析之前返回。我建议阅读有关承诺的内容以了解这一点。
解决方案是让承诺解析为您想要的值,然后在效果中等待它,然后再在组件状态中设置值。
import { useIsAuthenticated as isAuthenticated } from "@azure/msal-react";
import { createContext, useState, useEffect } from "react";
import { useMsal } from "@azure/msal-react";
import { msalConfig } from "../authConfig";
const initUser = () => ({
ADuserdatas: {
homeAccountId: "",
accountEnabled: "",
companyName: "",
createdDateTime: "",
department: "",
displayName: "",
givenName: "",
id: "",
jobTitle: "",
mail: "",
mobilePhone: "",
officeLocation: "",
surname: "",
userType: "",
},
language: "en",
});
const UserDatasFromMS = ({ instance, accounts }) => {
const callMsGraph = (token) => {};
const handleUser = () => {
instance
.acquireTokenSilent({
scopes: ["openid", "profile", "user.read"],
account: accounts[0],
authority: `https://login.microsoftonline.com/${msalConfig.auth.tenantId}`,
})
.then((response) =>
callMsGraph(response.accessToken).then((data) => ({
homeAccountId: response.account.homeAccountId,
accountEnabled: data.accountEnabled,
companyName: data.companyName,
createdDateTime: data.createdDateTime,
department: data.department,
displayName: data.displayName,
givenName: data.givenName,
id: data.id,
jobTitle: data.jobTitle,
mail: data.mail,
mobilePhone: data.mobilePhone,
officeLocatio: data.officeLocation,
surname: data.surname,
userType: data.userType,
}))
);
};
return handleUser();
};
export const UserContext = createContext({});
export const UserContextProvider = ({ children }) => {
const { instance, accounts } = useMsal();
const [datasFromMS, setDatasFromMS] = useState(initUser.ADuserdatas);
useEffect(() => {
if (!isAuthenticated) return;
UserDatasFromMS({ instance, accounts }).then((ADuserdatas) =>
setDatasFromMS({ADuserdatas})
);
}, [instance, accounts]);
return (
<UserContext.Provider
value={{
datasFromMS,
setDatasFromMS,
}}
>
{children}
</UserContext.Provider>
);
};