Singh
Siguiendo
Cómo usar async/await con axios en reaccionar
Estoy tratando de hacer una solicitud de obtención simple a mi servidor usando Async/Await en una aplicación React.js. El servidor carga un JSON simple en /data
que se parece a esto
JSON
{
id: 1,
name: "Aditya"
}
Puedo obtener los datos en mi aplicación React utilizando el método jquery ajax get simple. Sin embargo, quiero utilizar la biblioteca axios y Async/Await para seguir los estándares ES7. Mi código actual se ve así:
class App extends React.Component{
async getData(){
const res = await axios('/data');
console.log(res.json());
}
render(){
return(
<div>
{this.getData()}
</div>
);
}
}
Usando este enfoque me sale el siguiente error:
Los objetos no son válidos como un niño React (encontrado: [object Promise]). Si tenía la intención de representar una colección de niños, use una matriz en su lugar.
¿No lo estoy implementando correctamente?
TJ Crowder
Dos cuestiones saltan a la vista:
-
Su
getData
nunca devuelve nada, por lo que su promesa (async
funciones siempre devuelven una promesa) se cumplirá conundefined
si no rechaza -
El mensaje de error muestra claramente que estás tratando de cumplir directamente la promesa.
getData
devoluciones, en lugar de esperar a que se liquide y luego devolver el valor de cumplimiento
Direccionamiento #1: getData
debería devolver el resultado de llamar json
:
async getData(){
const res = await axios('/data');
return await res.json();
}
Dirección #2: Tendríamos que ver más de su código, pero fundamentalmente, no puede hacerlo
<SomeElement>{getData()}</SomeElement>
…porque eso no espera a la resolución. En su lugar, necesitarías usar getData
para establecer el estado:
this.getData().then(data => this.setState({data}))
.catch(err => { /*...handle the error...*/});
… y usa ese estado al renderizar:
<SomeElement>{this.state.data}</SomeElement>
Actualizar: ahora que nos ha mostrado su código, debe hacer algo como este:
class App extends React.Component{
async getData() {
const res = await axios('/data');
return await res.json(); // (Or whatever)
}
constructor(...args) {
super(...args);
this.state = {data: null};
}
componentDidMount() {
if (!this.state.data) {
this.getData().then(data => this.setState({data}))
.catch(err => { /*...handle the error...*/});
}
}
render() {
return (
<div>
{this.state.data ? <em>Loading...</em> : this.state.data}
</div>
);
}
}
Más actualización: Has indicado una preferencia por usar await
en componentDidMount
más bien que then
y catch
. Lo harías anidando un async
Función IIFE dentro de él y garantizar que la función no pueda lanzar. (componentDidMount
en sí mismo no puede ser async
nada consumirá esa promesa.) Por ejemplo:
class App extends React.Component{
async getData() {
const res = await axios('/data');
return await res.json(); // (Or whatever)
}
constructor(...args) {
super(...args);
this.state = {data: null};
}
componentDidMount() {
if (!this.state.data) {
(async () => {
try {
this.setState({data: await this.getData()});
} catch (e) {
//...handle the error...
}
})();
}
}
render() {
return (
<div>
{this.state.data ? <em>Loading...</em> : this.state.data}
</div>
);
}
}
-
Me dio este error “‘esto’ no está permitido antes de super ()”. Así que agregué super(); justo antes de “this.state = {data: null};” que luego resultó en un nuevo error: “‘getData’ no está definido no-undef”
– Singh
13 oct 2017 a las 15:54
-
@Morfsys: no creo que ese sea el mensaje de error exacto. 🙂 Yo dije “algo como esto”. He actualizado lo anterior, faltaba
this.
engetData
.–TJ Crowder
13 oct 2017 a las 15:57
-
.catch(err => { /*…manejar el error…*/}); se ejecuta ahora. Dice que res.json() no es una función.
– Singh
13 oct 2017 a las 16:16
-
Solo para tu información…
return res.json()
tendría que serreturn await res.json()
en el ejemplo anterior, ¿correcto? Si lo devuelve en la siguiente línea, la línea de retorno se ejecutará de inmediato en lugar de esperar a que la definaconst res
justo encima de.– dave4jr
9 mayo 2018 a las 22:13
-
@ dave4jr: No, no es necesario, pero puede ser una buena idea desde el punto de vista del mantenimiento del código, gracias. “Si lo devuelve en la siguiente línea, la línea de retorno se ejecutará de inmediato en lugar de esperar…” No, eso es incorrecto. los
return
la línea no se ejecutará hasta queawait axios('/data')
resuelve Así que el código sin elawait
funcionaría, la promesa creada porgetData
siendoasync
simplemente sería esclavo del devuelto porres.json()
. Pero desde un código de mantenimiento. pers., tienes razón, mejorawait
– porque sería fácil estropearlo al hacer cambios engetData
.–TJ Crowder
10 de mayo de 2018 a las 5:59
Singh
En mi experiencia de los últimos meses, me he dado cuenta de que la mejor manera de lograr esto es:
class App extends React.Component{
constructor(){
super();
this.state = {
serverResponse: ''
}
}
componentDidMount(){
this.getData();
}
async getData(){
const res = await axios.get('url-to-get-the-data');
const { data } = await res;
this.setState({serverResponse: data})
}
render(){
return(
<div>
{this.state.serverResponse}
</div>
);
}
}
Si está tratando de hacer una solicitud de publicación en eventos como un clic, llame getData()
funcione en el evento y reemplace el contenido de este modo:
async getData(username, password){
const res = await axios.post('url-to-post-the-data', {
username,
password
});
...
}
Además, si está realizando alguna solicitud cuando el componente está a punto de cargarse, simplemente reemplace async getData()
con async componentDidMount()
y cambie la función de render así:
render(){
return (
<div>{this.state.serverResponse}</div>
)
}
-
Esta es básicamente mi respuesta, reformulada. También: 1. No hagas
componentWillMount
unasync
función. React ignorará la promesa devuelta. 2. A menos queres.data
es un accesorio que devuelve una promesa, no tiene ningún sentido usarawait
al acceder a ella.–TJ Crowder
18 de diciembre de 2017 a las 8:13
-
Simplemente he tratado de simplificar la respuesta. Sin ofender, pero creo
then
ycatch
no es el último estándar (ES6) de seguimiento con una promesa. Además, res.json() no funcionaba para mí, por lo que tuve que reemplazarlo con res.data que viene junto con una promesa enGET
oPOST
solicitud.– Singh
18 de diciembre de 2017 a las 8:34
-
then
ycatch
son la forma ES2015 (también conocida como “ES6”) de lidiar con las promesas.async
/await
son la forma ES2017 (“ES8”). Pero solo puedes usarawait
dentro de unasync
función y hacercomponentWillMount
async
es crear una promesa que nunca se consumirá. Si quieres usarawait
en cambio, eso está bien, pero lo harías de manera diferente a simplemente abofetearasync
encomponentWillMount
. En cualquier caso, francamente, regresar dos meses después y publicar una respuesta que solo modifica la existente sin atribución no es genial.–TJ Crowder
18 de diciembre de 2017 a las 8:42
async fetchCatFacts() {
await axios.get("//localhost:8082/api_v1/orders", {})
.then((response) => {
this.catFacts = response.data.data;
console.log("resp", response.data);
});
render() funciona bien, ya que mencioné claramente que puedo obtener detalles cuando uso $.ajax(). ¿Qué código adicional debo agregar? Esta es una simple solicitud de obtención al servidor que utiliza los estándares ES7.
– Singh
13 oct 2017 a las 15:38
Idealmente, actualice su pregunta con un ejecutable ejemplo mínimo reproducible que demuestra el problema utilizando un marcador de posición para el ajax (por ejemplo,
setTimeout
o similar), usando Stack Snippets (el[<>]
botón de la barra de herramientas). Stack Snippets admite React, incluido JSX; aquí está cómo hacer uno.–TJ Crowder
13 oct 2017 a las 15:43
… pero el código agregado aclara absolutamente las cosas. 🙂
–TJ Crowder
13 oct 2017 a las 15:48
para tu información,
async/await
es parte de ES2017, no ES7 (ES2016).– Félix Kling
13 oct 2017 a las 17:20
Gracias por la información.
– Singh
13 oct 2017 a las 17:24