在 useEffect 上使用异步函数,该函数将一个同样设置为异步的 State 作为参数

时间:2021-03-16 15:55:25

标签: reactjs

我不知道如何命名这个问题,请随意编辑。

我正在使用一个提供项目(与登录名/密码唯一相关)和与这些项目的任务相关的状态列表的 API。它有两条路线:

  • 项目路由:接收一个 login 和一个 password 并返回其 ID 和名称:
{idProject: string, nome: string}
  • 状态路由:接收 idProject 并返回其状态数组
[{idStatus: string, area: string, descricao: string}]

我知道混合语言而不使用令牌是一种非常糟糕的做法,但我不是编写后端的人,我只是在使用它。由于我使用的是打字稿,我决定不翻译变量名称,否则类型会混乱,我很抱歉。

我创建了一个 services.tsx 来使用它:

import axios from "axios";

const api = axios.create({
  baseURL: "", // omitted for safety reasons
});

export const getUserPromise = async (login: string, password: string) => {
  const userPromise = api.get(`/projetos?login=${login}&senha=${password}`);
  return userPromise;
};

export const getAllStatusPromise = async (idProjeto: string) => {
  const AllStatusPromise = api.get(`/projetos/${idProjeto}/statusAreas`);
  return AllStatusPromise;
};

我的 App.tsx 定义了函数 getUser()getAllStatus(),用于处理 promise 并将它们存储在 userallStatus 状态。

它还定义了一个异步 getRequests() 函数,该函数在 useEffect() 上用于 await 调用 getUser()getAllStatus()

它还在 html 上打印结果:

import React, { useEffect, useState } from "react";
import { getUserPromise, getAllStatusPromise } from "./services";

const App: React.FC = () => {
  const [user, setUser] = useState({
    idProjeto: "0000",
    nome: "Fallback User",
  });

  const [allStatus, setAllStatus] = useState([
    {
      idStatus: "0000",
      area: "Fallback AllStatus",
      descricao: "Fallback allStatus",
    },
  ]);

  useEffect(() => {
    getRequests();
  }, []);

  const getRequests = async () => {
    const mocked_login = ""; // Omitted for safety reasons
    const mocked_password = ""; // Omitted for safety reasons

    await getUser(mocked_login, mocked_password);
    await getAllStatus(user.idProjeto);
  };

  const getUser = async (login: string, password: string) => {
    try {
      const userPromise = await getUserPromise(login, password);
      const user = userPromise.data;
      setUser(user);
    } catch (error) {
      console.log(error);
    }
  };

  const getAllStatus = async (idProjeto: string) => {
    try {
      const allStatusPromise = await getAllStatusPromise(idProjeto);
      const allStatus = allStatusPromise.data;
      setAllStatus(allStatus);
    } catch (error) {
      console.log(error);
    }
  };
  return (
    <div>
      <p>
        user.nome: {user.nome} | user.idProjeto: {user.idProjeto}
      </p>
      <p>Number of status: {allStatus.length}</p>
      {allStatus.map((status) => {
        return (
          <ul>
            Status:
            <li>status.area: {status.area}</li>
            <li>status.descricao: {status.descricao}</li>
            <li>status.idStatus: {status.idStatus}</li>
          </ul>
        );
      })}
    </div>
  );
};

export default App;

我使用 user 状态作为 getAllStatus() 的参数。

这段代码有效:

enter image description here

user 在呈现页面时已成功设置:与我的模拟登录名和密码相关的用户具有 projectId === 12345

但是,allStatus 没有预期值。它请求了后备 projectId 0000,它在 api 上返回 63 状态。但是,projecId 12345 没有 63 状态。它只有 5 个。

这意味着我的异步调用有问题。调用 user.projectId 时,1245 状态未设置为 getAllStatus()。但是当页面呈现时,这就是呈现用户工作但对 getAllStatus 的顺序调用不工作的原因。

如何强制 getAllStatus() 等待 getUser() 中的状态更改完成?

1 个答案:

答案 0 :(得分:1)

useState 有时不会立即改变状态。在您的情况下,您可以返回用户并在您的 getRequests 函数中获取它。

const getRequests = async () => {
    const mocked_login = ""; // Omitted for safety reasons
    const mocked_password = ""; // Omitted for safety reasons

    const user = await getUser(mocked_login, mocked_password); // get the returned user
    await getAllStatus(user.idProjeto);
  };

  const getUser = async (login: string, password: string) => {
    try {
      const userPromise = await getUserPromise(login, password);
      const user = userPromise.data;
      setUser(user);
      return user;    // return it here
    } catch (error) {
      console.log(error);    

    }
  };