Si el usuario escribe la id en la entrada, me gustaría obtener la publicación por identificación específica escrita por el usuario. De lo contrario, me gustaría obtener una serie completa de publicaciones y luego obtener una identificación de los datos obtenidos. Sé que no tiene sentido, pero solo para pruebas.
No funciona, porque useState funciona de forma asíncrona. Probé algunas soluciones, pero todas se veían muy feas.
Recibí un error:
Cannot read properties of undefined (reading 'id') Porque setPosts aún no se ha configurado.
¿Cuál es la mejor manera clara de manejar este caso?
import { useState } from "react"; export default function App() { const [id, setId] = useState(""); const [post, setPost] = useState(null); const [posts, setPosts] = useState([]); const fetchPost = async (id) => { const res = await axios.get( `https://jsonplaceholder.typicode.com/posts/${id}` ); setPost(res.data); }; const fetchPosts = async () => { const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`); setPosts(res.data); }; const onSubmit = async (e) => { e.preventDefault(); if (id) { await fetchPost(id); } else { await fetchPosts(); await fetchPost(posts[0].id); } }; return ( <div className="App"> <form onSubmit={onSubmit}> <input type="text" onChange={(e) => setId(e.target.value)} /> <button type="submit">submit</button> </form> </div> ); }Puede tratar fetchPosts como un efecto secundario y envolver fetchPost(posts[0].id) en un useEffect depende de las posts .
O simplemente use el resultado directamente en onSubmit() (suponiendo que no necesita posts para otra cosa).
const fetchPosts = async () => { const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`); // setPosts(res.data); // this state is transitory and not used directly by the render return res.data; }; const onSubmit = async (e) => { e.preventDefault(); if (id) { await fetchPost(id); } else { const posts = await fetchPosts(); // Only used as part of submit event? await fetchPost(posts[0].id); } }; return ( <div className="App"> <form onSubmit={onSubmit}> <input type="text" onChange={(e) => setId(e.target.value)} /> <button type="submit">submit</button> </form> <div>{(post && post.title) || "No post yet"}</div> </div> );Al igual que dijiste, useState funciona de forma asíncrona , si deseas hacer algo después de mutarlo, tendrás que usar useEffect y configurar las publicaciones como sus argumentos, ahora, cada vez que las publicaciones muten, tu función se ejecutará y se enviará el primer índice de la matriz. a fetchPost(id) ,
import axios from "axios"; import "./styles.css"; import { useEffect, useState } from "react"; export default function App() { const [id, setId] = useState(""); const [post, setPost] = useState(null); const [posts, setPosts] = useState([]); useEffect(() => { if (posts.length) { fetchPost(posts[0].id); } }, [posts]); const fetchPost = async (id) => { console.log(`fetching ${id}`); const res = await axios.get( `https://jsonplaceholder.typicode.com/posts/${id}` ); console.log(res.data); setPost(res.data); }; const fetchPosts = async () => { console.log(`fetching all posts`); const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`); setPosts(res.data); }; const onSubmit = async (e) => { e.preventDefault(); if (id) { await fetchPost(id); } else { await fetchPosts(); // res = await fetchPost(posts[0].id); we dont need it here it defined in useffect function } }; const setDefaultId = (e) => { setId(e.target.value); }; return ( <div className="App"> <form onSubmit={onSubmit}> <input type="text" onChange={(e) => setDefaultId(e)} /> <button type="submit">submit</button> </form> </div> ); }También considere nunca actualizar el estado directamente en su función de devolución, ya que causará problemas de rendimiento
El problema está en el método "fetchPost". Dentro de este método, tienes dos variables con el mismo nombre. "id" del enlace de estado e "id" del parámetro de función. Puede resolver el problema cambiando el nombre de una de esas variables.
Una cosa más, si "id" no tiene valor, su forma de obtener la primera publicación no funcionará porque el método de espera no esperará al cambio de estado.
He editado un poco el código para resolver ambos problemas.
import { useState } from 'react'; import axios from 'axios'; export default function App() { const [id, setId] = useState(''); const [post, setPost] = useState(null); const fetchPost = async (idProp) => { const res = await axios.get( `https://jsonplaceholder.typicode.com/posts/${idProp}`, ); setPost(res.data); }; const fetchPosts = async () => { const res = await axios.get('https://jsonplaceholder.typicode.com/posts'); await fetchPost(res.data[0].id); }; const onSubmit = async (e) => { e.preventDefault(); if (id) { await fetchPost(id); } else { await fetchPosts(); } }; return ( <div className="App"> <form onSubmit={onSubmit}> <input type="text" onChange={(e) => { setId(e.target.value); }} /> <button type="submit">submit</button> </form> </div> ); }Espero haberte ayudado.