React - 在渲染之前等待承诺

Vel*_*o89 5 render async-await reactjs

我无法弄清楚这一点,如果你能指出我正确的方向。在我的 NavMenu.js 我有登录(两个输入和一个提交按钮,我调用handleSubmit()

handleSubmit()我检查用户登录凭据时效果很好,但在我确认登录后,我继续执行下一次获取以检查用户角色(并返回承诺)和应用程序中的可见性

Helper.js

function getAllRoles(formName, sessionVarName) {

    var roleData = [];
    var roleId = sessionStorage.getItem('UserLoggedRoleId');

    fetch('api/User/GetUserRole/', {
    'method': 'POST',
    headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
    },
    'body':
        JSON.stringify({
            'roleId': roleId,
            'formName': formName
        })
    }).then(roleResponse => roleResponse.json())
    .then(data => {
        sessionStorage.setItem(sessionVarName, JSON.stringify(data));
        roleData = data;
    });

  var result = Promise.resolve(roleData)

  return result;
}

function checkRoleVisibility(userRoles, role) {} <-- return true or false

export {
  getAllRoles ,
  checkRoleVisibility   
};
Run Code Online (Sandbox Code Playgroud)

在 NavMenu.js 中

import { getAllRoles, checkRoleVisibility } from './common/Helper';

handleSubmit() {

 fetch('api/User/UserAuthentification/', 
 ....then(response => {
       if (response.ok) {
               this.setState(prevState => ({ userLogged: !prevState.userLogged }))

               response.json().then(value => {

               sessionStorage.setItem('UserLogged', true);
               sessionStorage.setItem('UserLabelSession', this.state.userLabel);
               sessionStorage.setItem('UserLoggedRoleId', value.userRole.roleID);

               getAllRoles('NavMenu', 'UserLoggedRoles')
                     .then(roleData => {
                            this.setState({
                                loggedUserRoles: roleData,
                                loading: false
                            });
                        });

               this.props.alert.success("Dobro dosli");
        })
   }
}
Run Code Online (Sandbox Code Playgroud)

但问题来了,就其render()本身而言,我有一个navBar调用

checkRoleVisibility(this.state.loggedUserRoles, 'SeeTabRadniNalozi')
Run Code Online (Sandbox Code Playgroud)

from helper,它this.state.loggedUserRoles作为参数发送,假设填写 fetch fromhandleSubmit()但它是未定义的,fetch 完成,设置loading为 true,渲染完成,它不显示任何内容

我有this.state.loading并基于它我表现出控制......

    let navMenu = this.state.loading ? <div className="loaderPosition">
        <Loader type="Watch" color="#1082F3" height="200" width="200" />
    </div> : !this.state.userLogged ? logInControl : navBar;
Run Code Online (Sandbox Code Playgroud)

如果我在控制器上放置一个断点,我可以看到我的方法正在被getAllRoles函数调用,但我也可以看到该应用程序继续呈现并且不等待承诺返回到loggedUserRoles.

所以问题是,为什么在将加载设置为 true 之前,渲染既不等待我的角色获取也不等待 promise 解决?

我检查了这个答案Wait for react-promise to resolve before render and I put this.setState({ loading: false });on componentDidMount()but then loading div is full time

Bjö*_*ing 2

据我所知,你正在打电话

this.setState(prevState => ({ userLogged: !prevState.userLogged }))
Run Code Online (Sandbox Code Playgroud)

如果响应没问题。这将导致 React 进行异步调用,以便在有时间的时候设置新的 State。

但你需要来自的资源

this.setState({
  loggedUserRoles: roleData,
  loading: false
});
Run Code Online (Sandbox Code Playgroud)

每当你想设置userLogged为 true 时,对吗?

因此,React 可能会在您设置之前调用 render,loggedUserRoles但在userLogged设置为 true 之后。如果我理解正确的话,这会导致错误。

您可以简单地userLogged与其他人一起设置状态,如下所示:

this.setState({
  userLogged: true,
  loggedUserRoles: roleData,
  loading: false
});
Run Code Online (Sandbox Code Playgroud)

编辑:

此外,您想更改 getAllRoles 内部的 Promise 创建。你回来了

var result = Promise.resolve(roleData)

return result;
Run Code Online (Sandbox Code Playgroud)

这将直接导致空数组,因为这是 的初始值roleData。因此,您总是从该方法返回一个空数组,并且不必担心获取的结果。

你有多种方法可以解决这个问题。我更喜欢使用 async/await 的干净且可读的方式:

async getAllRoles(formName, sessionVarName){
  var roleId = sessionStorage.getItem('UserLoggedRoleId');

  const response = await fetch(...);
  const data = response.json();

  sessionStorage.setItem(sessionVarName, JSON.stringify(data));
  return data;
Run Code Online (Sandbox Code Playgroud)

或者如果你想继续使用 Promise:

function getAllRoles(formName, sessionVarName){
  return new Promise((resolve, reject) => {
    var roleId = sessionStorage.getItem('UserLoggedRoleId');

    fetch(...)
    .then(roleResponse => roleResponse.json())
    .then(data => {
      sessionStorage.setItem(sessionVarName, JSON.stringify(data));
      resolve(data);
    });
Run Code Online (Sandbox Code Playgroud)