#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() {
/*...*/
}
}