Estoy tratando de realizar un cambio de estado y luego quiero hacer una solicitud de API. Pero como useState es asíncrono, no puedo hacer eso. Intenté usar el gancho useEffect() pero es imposible encontrar el elemento de matriz exacto que se cambió.
En toggleCompleted() el valor anterior para updatedTask porque setTasks es asíncrono.
Aplicación.js
import { useState, useEffect } from 'react' const App = () => { const [tasks, setTasks] = useState([]) const toggleCompleted = id => { setTasks( tasks.map(task => { return task.id === id ? { ...task, isCompleted: !task.isCompleted } : task }) ) // This will get the old value const updatedTask = tasks.find(task => task.id === id) // PUT request here fetch(`${api_url}/tasks/${id}`, { method: 'PUT', body: JSON.stringify(updatedTask) }) } } export default App También intenté usar el useEffect , pero obtengo la matriz de tasks completa y no la tarea individual que se actualizó, por lo que no puedo usar esto para realizar una solicitud PUT a mi API de back-end.
useEffect(() => { // unable to get the exact one task that was updated }, [tasks])¿Por qué no hacerlo así?
import { useState, useEffect } from 'react' const App = () => { const [tasks, setTasks] = useState([]) const toggleCompleted = id => { let updatedTask = tasks.filter(task => task.id === id) updatedTask.isCompleted = !updatedTask.isCompleted // PUT request here fetch(`${api_url}/tasks/${id}`, { method: 'PUT', body: JSON.stringify(updatedTask) }) setState(tasks.map(task => task.id === id ? updatedTask : task)) } } export default App Esto debería solucionar tu problema.
Básicamente, capturamos la tarea que queremos actualizar, la manipulamos como queramos y finalmente establecemos el estado.
Terminé refactorizando mi código a donde primero obtengo y actualizo el elemento que se usa tanto para actualizar el estado como para hacer la llamada a la API.
const toggleReminder = id => { let updatedTask = tasks.find(task => task.id === id) updatedTask.isCompleted = !updatedTask.isCompleted setTasks( tasks.map(task => { return task.id === id ? updatedTask : task }) ) fetch(`${api_url}/tasks/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updatedTask) }) }prueba este
import { useState, useEffect } from 'react' const App = () => { const [tasks, setTasks] = useState([]) const toggleCompleted = async (id) => { const currentTask = tasks.find(task => task.id === id); const updatedTask = {...currentTask, isCompleted: !currentTask.isCompleted}; await fetch(`${api_url}/tasks/${id}`, { method: 'PUT', body: JSON.stringify(updatedTask) }); setTasks(tasks.map(task => task.id === id?updatedTask :task)); } } export default Apppuede usar la función normal en lugar de async/await y poner setTasks en .then pero creo que es más simple.