Si eres nuevo en React, y quizás solo hayas jugado con la creación de aplicaciones de mostrador y tareas pendientes, es posible que aún no hayas encontrado la necesidad de obtener datos para tu aplicación. Es probable que llegue un momento en el que necesite hacer esto, ya que las aplicaciones React son las más adecuadas para situaciones en las que maneja tanto datos como estados.
El primer conjunto de datos que puede necesitar manejar podría estar codificado en su aplicación React, como lo hicimos para esta demostración de nuestro tutorial Error Boundary:
Consulte el límite de error de lápiz 0 de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
¿Qué sucede si desea manejar datos de una API? Ese es el propósito de este tutorial. Específicamente, usaremos la API Fetch y axios como ejemplos de cómo solicitar y usar datos.
La API de Fetch
La API Fetch proporciona una interfaz para buscar recursos. Lo usaremos para obtener datos de una API de terceros y veremos cómo usarlo al obtener datos de una API construida internamente.
Usar Fetch con una API de terceros
Consulte Pen React Fetch API Pen 1 de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Buscaremos usuarios aleatorios de JSONPlaceholder, una API REST en línea falsa para realizar pruebas. Comencemos creando nuestro componente y declarando algún estado predeterminado.
class App extends React.Component {
state = {
isLoading: true,
users: [],
error: null
}
render() {
<React.Fragment>
</React.Fragment>
}
}
Es probable que haya un retraso cuando la red solicite datos. Pueden ser unos segundos o quizás unos milisegundos. De cualquier manera, durante este retraso, es una buena práctica informar a los usuarios que algo está sucediendo mientras se procesa la solicitud.
Para hacer eso usaremos isLoading
para mostrar el mensaje de carga o los datos solicitados. Los datos se mostrarán cuando isLoading
es false
, de lo contrario, se mostrará un mensaje de carga en la pantalla. Entonces el render()
El método se verá así:
render() {
const { isLoading, users, error } = this.state;
return (
<React.Fragment>
<h1>Random User</h1>
// Display a message if we encounter an error
{error ? <p>{error.message}</p> : null}
// Here's our data check
{!isLoading ? (
users.map(user => {
const { username, name, email } = user;
return (
<div key={username}>
<p>Name: {name}</p>
<p>Email Address: {email}</p>
<hr />
</div>
);
})
// If there is a delay in data, let's let the user know it's loading
) : (
<h3>Loading...</h3>
)}
</React.Fragment>
);
}
El código básicamente hace esto:
- De-estructuras
isLoading
,users
yerror
desde el estado de la aplicación para que no tengamos que seguir escribiendothis.state
. - Imprime un mensaje si la aplicación encuentra un error al establecer una conexión
- Comprueba si se están cargando datos
- Si no se está cargando, entonces debemos tener los datos, entonces los mostramos
- Si se está cargando, debemos seguir trabajando en ello y mostrar “Cargando …” mientras la aplicación está funcionando.
Para que los pasos 3-5 funcionen, debemos realizar la solicitud para obtener datos de una API. Aquí es donde la API JSONplaceholder será útil para nuestro ejemplo.
fetchUsers() {
// Where we're fetching data from
fetch(`https://jsonplaceholder.typicode.com/users`)
// We get the API response and receive data in JSON format...
.then(response => response.json())
// ...then we update the users state
.then(data =>
this.setState({
users: data,
isLoading: false,
})
)
// Catch any errors we hit and update the app
.catch(error => this.setState({ error, isLoading: false }));
}
Creamos un método llamado fetchUser()
y utilícelo para hacer exactamente lo que podría pensar: solicitar datos de usuario desde el punto final de la API y buscarlos para nuestra aplicación. Fetch es una API basada en promesas que devuelve un objeto de respuesta. Entonces, usamos el json()
método para obtener el objeto de respuesta que se almacena en los datos y se utiliza para actualizar el estado de los usuarios en nuestra aplicación. También necesitamos cambiar el estado de isLoading
a false
para que nuestra aplicación sepa que la carga se ha completado y todo está claro para renderizar los datos.
El hecho de que Fetch se base en promesas significa que también podemos detectar errores utilizando el .catch()
método. Cualquier error encontrado se usa como un valor para actualizar el estado de nuestro error. ¡Práctico!
La primera vez que se procesa la aplicación, los datos no se habrán recibido; puede tardar unos segundos. Queremos activar el método para buscar los usuarios cuando se puede acceder al estado de la aplicación para una actualización y la aplicación se vuelve a renderizar. Reaccionar componentDidMount()
es el mejor lugar para esto, así que colocaremos el fetchUsers()
método en él.
componentDidMount() {
this.fetchUsers();
}
Uso de Fetch con API propia
Hasta ahora, hemos visto cómo utilizar los datos de otra persona en una aplicación. Pero, ¿y si trabajamos con nuestros propios datos en nuestra propia API? Eso es lo que vamos a cubrir ahora mismo.
Consulte Pen React Fetch API Pen 2 de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Creé una API que está disponible en GitHub. La respuesta JSON que obtiene se ha colocado en AWS; eso es lo que usaremos para este tutorial.
Como hicimos antes, creemos nuestro componente y configuremos un estado predeterminado.
class App extends React.Component {
state = {
isLoading: true,
posts: [],
error: null
}
render() {
<React.Fragment>
</React.Fragment>
}
}
Nuestro método para recorrer los datos será diferente al que usamos antes, pero solo debido a la estructura de los datos, que será diferente. Puede ver la diferencia entre nuestra estructura de datos aquí y la que obtuvimos de JSONPlaceholder.
Así es como render()
El método se verá así para nuestra API:
render() {
const { isLoading, posts, error } = this.state;
return (
<React.Fragment>
<h1>React Fetch - Blog</h1>
<hr />
{!isLoading ? Object.keys(posts).map(key => <Post key={key} body={posts[key]} />) : <h3>Loading...</h3>}
</React.Fragment>
);
}
Vamos a romper la lógica
{
!isLoading ?
Object.keys(posts).map(key => <Post key={key} body={posts[key]} />)
: <h3>Loading...</h3>
}
Cuándo isLoading
no es true
, devolvemos una matriz, la asignamos y pasamos la información al componente Post como accesorios. De lo contrario, mostramos un mensaje “Cargando …” mientras la aplicación está funcionando. Muy similar a antes.
El método para buscar publicaciones se verá como el que se usó en la primera parte.
fetchPosts() {
// The API where we're fetching data from
fetch(`https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json`)
// We get a response and receive the data in JSON format...
.then(response => response.json())
// ...then we update the state of our application
.then(
data =>
this.setState({
posts: data,
isLoading: false,
})
)
// If we catch errors instead of a response, let's update the app
.catch(error => this.setState({ error, isLoading: false }));
}
Ahora podemos llamar al fetchPosts
método dentro de un componentDidMount()
método
componentDidMount() {
this.fetchPosts();
}
En el componente Publicar, mapeamos los accesorios que recibimos y mostramos el título y el contenido de cada publicación:
const Post = ({ body }) => {
return (
<div>
{body.map(post => {
const { _id, title, content } = post;
return (
<div key={_id}>
<h2>{title}</h2>
<p>{content}</p>
<hr />
</div>
);
})}
</div>
);
};
¡Ahí lo tenemos! Ahora sabemos cómo utilizar la API Fetch para solicitar datos de diferentes fuentes y ponerlos en práctica en una aplicación. Chocar los cinco. ✋
axios
Bien, hemos pasado una buena cantidad de tiempo mirando la API de Fetch y ahora vamos a centrar nuestra atención en axios.
Al igual que la API Fetch, axios es una forma en que podemos realizar una solicitud de datos para usar en nuestra aplicación. Donde brilla axios es cómo le permite enviar una solicitud asincrónica a los puntos finales REST. Esto es útil cuando se trabaja con la API REST en un proyecto de React, digamos un CMS de WordPress sin cabeza.
Existe un debate en curso sobre si Fetch es mejor que axios y viceversa. No vamos a profundizar en eso aquí porque, bueno, puede elegir la herramienta adecuada para el trabajo adecuado. Si tiene curiosidad sobre los puntos de cada lado, puede leer aquí y aquí.
Usar axios con una API de terceros
Vea el Pen React Axios 1 Pen de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Como hicimos con la API Fetch, comencemos solicitando datos de una API. Para este, buscaremos usuarios aleatorios de la API de usuario aleatorio.
Primero, creamos el componente de la aplicación como lo hemos hecho antes:
class App extends React.Component {
state = {
users: [],
isLoading: true,
errors: null
};
render() {
return (
<React.Fragment>
</React.Fragment>
);
}
}
La idea sigue siendo la misma: verifique si la carga está en proceso y renderice los datos que obtenemos o deje que el usuario sepa que las cosas todavía se están cargando.
Para realizar la solicitud a la API, necesitaremos crear una función. Llamaremos a la función getUsers()
. Dentro de él, haremos la solicitud a la API usando axios. Veamos cómo se ve eso antes de explicar más.
getUsers() {
// We're using axios instead of Fetch
axios
// The API we're requesting data from
.get("https://randomuser.me/api/?results=5")
// Once we get a response, we'll map the API endpoints to our props
.then(response =>
response.data.results.map(user => ({
name: `${user.name.first} ${user.name.last}`,
username: `${user.login.username}`,
email: `${user.email}`,
image: `${user.picture.thumbnail}`
}))
)
// Let's make sure to change the loading state to display the data
.then(users => {
this.setState({
users,
isLoading: false
});
})
// We can still use the `.catch()` method since axios is promise-based
.catch(error => this.setState({ error, isLoading: false }));
}
Muy diferente de los ejemplos de Fetch, ¿verdad? La estructura básica es bastante similar, pero ahora estamos en el negocio de mapear datos entre puntos finales.
La solicitud GET se transmite desde la URL de la API como parámetro. La respuesta que obtenemos de la API contiene un objeto llamado data
y que contiene otros objetos. La información que queremos está disponible en data.results
, que es una matriz de objetos que contiene los datos de usuarios individuales.
Aquí vamos de nuevo con llamar a nuestro método dentro del componentDidMount()
método:
componentDidMount() {
this.getUsers();
}
Alternativamente, puede hacer esto en su lugar y básicamente combinar estos dos primeros pasos:
componentDidMount() {
axios
.get("https://randomuser.me/api/?results=5")
.then(response =>
response.data.results.map(user => ({
name: `${user.name.first} ${user.name.last}`,
username: `${user.login.username}`,
email: `${user.email}`,
image: `${user.picture.thumbnail}`
}))
)
.then(users => {
this.setState({
users,
isLoading: false
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
Si está codificando localmente desde su máquina, puede editar temporalmente el getUsers()
función para verse así:
getUsers() {
axios
.get("https://randomuser.me/api/?results=5")
.then(response => console.log(response))
.catch(error => this.setState({ error, isLoading: false }));
}
Su consola debería obtener algo similar a esto:
Hacemos un mapeo a través de la matriz de resultados para obtener la información que necesitamos para cada usuario. La matriz de usuarios se utiliza para establecer un nuevo valor para nuestro users
Expresar. Una vez hecho esto, podemos cambiar el valor de isLoading
.
Por defecto, isLoading
se establece en true
. Cuando el estado de users
se actualiza, queremos cambiar el valor de isLoading
a false
ya que esta es la señal que nuestra aplicación está buscando para hacer el cambio de “Cargando …” a datos renderizados.
render() {
const { isLoading, users } = this.state;
return (
<React.Fragment>
<h2>Random User</h2>
<div>
{!isLoading ? (
users.map(user => {
const { username, name, email, image } = user;
return (
<div key={username}>
<p>{name}</p>
<div>
<img src={image} alt={name} />
</div>
<p>{email}</p>
<hr />
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
Si registra el users
estado en la consola, verá que es una matriz de objetos:
La matriz vacía muestra el valor antes de que se obtuvieran los datos. Los datos devueltos contienen solo el name
, username
, email address
y image
de usuarios individuales porque esos son los puntos finales que trazamos. Hay muchos más datos disponibles en la API, por supuesto, pero tendríamos que agregarlos a nuestro getUsers
método.
Usando axios con su propia API
Vea el Pen React Axios 2 Pen de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Ha visto cómo usar axios con una API de terceros, pero podemos ver cómo es solicitar datos de nuestra propia API, tal como hicimos con la API Fetch. De hecho, usemos el mismo archivo JSON que usamos para Fetch para que podamos ver la diferencia entre los dos enfoques.
Aquí está todo junto:
class App extends React.Component {
// State will apply to the posts object which is set to loading by default
state = {
posts: [],
isLoading: true,
errors: null
};
// Now we're going to make a request for data using axios
getPosts() {
axios
// This is where the data is hosted
.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json")
// Once we get a response and store data, let's change the loading state
.then(response => {
this.setState({
posts: response.data.posts,
isLoading: false
});
})
// If we catch any errors connecting, let's update accordingly
.catch(error => this.setState({ error, isLoading: false }));
}
// Let's our app know we're ready to render the data
componentDidMount() {
this.getPosts();
}
// Putting that data to use
render() {
const { isLoading, posts } = this.state;
return (
<React.Fragment>
<h2>Random Post</h2>
<div>
{!isLoading ? (
posts.map(post => {
const { _id, title, content } = post;
return (
<div key={_id}>
<h2>{title}</h2>
<p>{content}</p>
<hr />
</div>
);
})
) : (
<p>Loading...</p>
)}
</div>
</React.Fragment>
);
}
}
La principal diferencia entre este método y el uso de axios para obtener datos de un tercero es cómo se formatean los datos. Estamos obteniendo JSON directo de esta manera en lugar de mapear puntos finales.
Los datos de las publicaciones que obtenemos de la API se utilizan para actualizar el valor del componente posts
Expresar. Con esto, podemos mapear a través de la matriz de publicaciones en render()
. Entonces obtenemos el id
, title
y content
de cada publicación utilizando la desestructuración de ES6, que luego se muestra al usuario.
Como hicimos antes, lo que se muestra depende del valor de isLoading
. Cuando establecemos un nuevo estado para posts
utilizando los datos obtenidos de la API, tuvimos que establecer un nuevo estado para isLoading
, también. Luego, finalmente podemos dejar que el usuario sepa que los datos se están cargando o renderizar los datos que hemos recibido.
async y aguardar
Otra cosa que la naturaleza basada en promesas de axios nos permite hacer es aprovechar async
y await
. Usando esto, el getPosts()
La función se verá así.
async getPosts() {
const response = await axios.get("https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json");
try {
this.setState({
posts: response.data.posts,
isLoading: false
});
} catch (error) {
this.setState({ error, isLoading: false });
}
}
Instancia base
Con axios, es posible crear una instancia base donde colocamos la URL de nuestra API así:
const api = axios.create({
baseURL: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/posts.json"
});
… luego utilícelo de esta manera:
async getPosts() {
const response = await api.get();
try {
this.setState({
posts: response.data.posts,
isLoading: false
});
} catch (error) {
this.setState({ error, isLoading: false });
}
}
Simplemente una buena forma de abstraer la URL de la API.
¡Ahora, data todas las cosas!
A medida que construya aplicaciones React, se encontrará con muchos escenarios en los que desea manejar datos de una API. Es de esperar que se sienta armado y listo para utilizar datos de una variedad de fuentes con opciones sobre cómo solicitarlos.
¿Quieres jugar con más datos? Sarah escribió recientemente los pasos para crear su propia API sin servidor a partir de una lista de API públicas.