Установка состояния с помощью функции, которая возвращает вызов API, но мое состояние возвращает обещание

#reactjs #typescript #api

#reactjs #typescript #API

Вопрос:

У меня есть отдельная функция в API.js файл, который выполняет HTTP-запрос «get» для извлечения данных обратно в виде массива объектов. Я импортировал эту функцию в другой компонент React и вызвал функцию для setState . Когда я утешаю.запишите значение, которое возвращает обещание. Я также пытался использовать async / await, но я не уверен, хорошо ли это работает с typescript, поскольку значение tableData становится неопределенным.

В конечном счете, я хочу передать данные API обратно в компонент таблицы, а затем отобразить данные внутри таблицы, но я либо получаю обратно пустой объект, либо неопределенный. Есть ли что-то, чего мне не хватает?

Компонент машинописи Mainscreen.tsx

 import { msalInstance } from '../auth/Auth';
//import AccountDetails from './AccountDetails';
import Form from "../components/Form/Form";
import { getTenantInfo } from "../API/API";
import Table from "./Table/Table";
import Footer from "./Footer/Footer";


class MainScreen extends React.Component {
    state = {
        userName: '',
        account: [],
        tableData: []
    }

    public componentDidMount(): void {
        const account: any = msalInstance.getAccount();
        const tableData =  getTenantInfo();
        console.log('tableData', tableData)
        this.setState({
            userName: account.userName, 
            account: account,
            tableData: tableData
        });
    }

    //     async componentDidMount()  {
    //     const account = await msalInstance.getAccount();
    //     const tableData = await  getTenantInfo();
    //     console.log('tableData', this.state.tableData)
    //     this.setState({
    //         userName: account.userName, 
    //         account: account,
    //         tableData: tableData
    //     });
    // }

    render(){
        
        return(
        <div className='App'>
            <Header style={{height:"100px"}}>
                <Logo />
                <p>Welcome {this.state.userName}!</p>
                <Button id="logout-btn" onClick = {() => {msalInstance.logout()}}>Logout</Button>
            </Header>
            
            
            <Form />
            <Table tableData={ this.state.tableData } />
            <Footer />
        </div>
        )
    }
}

export default MainScreen;```

---------------------------------------------------------------------------------------------------------

Table.js - React Component

    ```import React from "react";
    
    const Table = ({ tableData }) => {
      return (
        <div>
          <h1>Tenant Information</h1>
          <table>
            <thead>
              <tr>
                <th>Tenant</th>
                <th>Secrets Rotated</th>
                <th>Resident Token Rotation</th>
                <th>Delete</th>
              </tr>
            </thead>
            <tbody>
                {console.log('tableData, null, 4'   JSON.stringify(tableData, null, 4))}
                { (tableData.length > 0) ? tableData.map( (data, index) => {
                    return (
                        <tr key={ index }>
                            {console.log('data'   data)}
                            <td></td>
                            <td>{ data[index].last_rotation }</td>
                            {/* <td>{ new Date() }</td>
                            <td>{ data.id }</td> */}
                        </tr>
                    )
    
                }) : <tr><td colSpan="5">Loading...</td></tr> }
            </tbody>
          </table>
        </div>
      );
    };
    
    export default Table;```

  

Комментарии:

1. Кроме того, Async / await используется в функции для выполнения вызова API в другой папке API — не показано выше

2. Добро пожаловать в SO. Можете ли вы также добавить код, который выполняет соответствующий вызов API? Если вы получаете обещание при регистрации ответа, я подозреваю, что вы что-то упускаете в этом вызове API.

3. msalInstance.getAccount() также является асинхронным? или просто getTenantInfo()

4. export async function getTenantInfo() { try { const res = await axios.get('<url>'); return res.data; } catch (error) { return error.res.data; } }

5. msalinsatnce.getAccount() не является асинхронным, но я мог бы попытаться преобразовать его в асинхронный

Ответ №1:

При работе с асинхронным вызовом мы хотим дождаться получения данных, а затем вызвать setState их для сохранения. Если msalInstance.getAccount() и getTenantInfo() оба async , то мы хотим обрабатывать их независимо, а не устанавливать состояние для обоих вместе. Каждый должен иметь возможность сохранять свое состояние, как только оно разрешится.

Вы установили начальные значения по умолчанию в своем состоянии пустых массивов и пустых строк, поэтому не должно быть никаких ошибок при попытке рендеринга до завершения обещаний.

Вы можете использовать синтаксис async/await или promise/then . Это просто синтаксическая разница, и в любом случае это обещание за кулисами, но async/await обычно предпочтительнее более новый синтаксис.

Я помещаю два действия в отдельные методы, из которых мы затем будем вызывать componentDidMount .

 class MainScreen extends React.Component {
  state = {
    userName: '',
    account: [],
    tableData: []
  }

  public componentDidMount(): void {
    // initiates both actions at the same time, not in order
    this.loadAccount();
    this.loadTableData();
  }

  private async loadTableData() {
    const tableData = await getTenantInfo();
    console.log('tableData', tableData)
    this.setState({
      tableData
    });
  }

  private async loadAccount() {
    const account: any = await msalInstance.getAccount(); // fix this any!
    this.setState({
      userName: account.userName,
      account: account,
    });
  }

  render() {
     /*...*/
  }
}