Estoy haciendo un formulario de asistencia donde los maestros pueden marcar quién está ausente y quién no y verificar quién estuvo ausente los días anteriores. Tengo la fecha actual en la parte superior y un botón que le permite cambiar la fecha hacia adelante y hacia atrás. Sin embargo, cuando trato de aumentar el valor, funciona bien, pero luego, cuando lo disminuyo, primero aumenta en uno y luego disminuye después de cada clic.
const [date, setDate] = useState() var today = new Date(); var dd = parseInt(String(today.getDate()).padStart(2, '0')); var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! var yyyy = today.getFullYear(); today = dd + '/' + mm + '/' + yyyy; useEffect(() => { setDate(today) }, []) const[newDay, setNewDay] = useState(dd) const changeToTomorrow = () => { setNewDay(newDay + 1) setDate(newDay + '/' + mm + '/' + yyyy) console.log(date) } const changeToYesterday = () => { setNewDay(newDay - 1) setDate(newDay + '/' + mm + '/' + yyyy) } return ( <div className="attendance-today-container"> <h1>Daily attendance</h1> <div className='change-date-container'> <div className='change-date'> <i class="fas fa-arrow-left" onClick={changeToYesterday}></i> <p>{date}</p> <i class="fas fa-arrow-right" onClick={changeToTomorrow}></i> </div> </div>Cuando actualiza un estado usando setNewDay(newDay + 1) , la variable newDay no se actualiza de inmediato. Entonces, cuando setDate(newDay + '/' + mm + '/' + yyyy) todavía usa el valor anterior de newDay para actualizar la date .
Tiene el estado inicial newDay = 10 date = 10/xx/xx , luego hace clic en el botón de aumento y se ejecuta el siguiente código. setNewDay(10 + 1) setDate(10 + '/' + mm + '/' + yyyy)
Después de reaccionar, renderiza el componente con un nuevo estado, obtuvo newDay = 11 date = 10/xx/xx en el siguiente clic para aumentar, obtendría setNewDay(11 + 1) setDate(11 + '/' + mm + '/' + yyyy)
Entonces, la date de la variable de fecha siempre está un paso atrás.
deberías hacer algo como
let nextDay = newDay + 1 setNewDay(nextDay) setDate(nextDay + '/' + mm + '/' + yyyy)en ambas funciones
Está tratando de establecer dos estados seguidos mientras que son asíncronos y es posible que no le den el valor actualizado de newDay en el momento en que establece la fecha.
Una solución rápida puede ser la siguiente (reorganizo un poco el código con espacios):
import {useState, useEffect} from "react"; export default function SomeComponent() { const [date, setDate] = useState() var today = new Date(); var dd = parseInt(String(today.getDate()).padStart(2, '0')); var mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0! var yyyy = today.getFullYear(); today = dd + '/' + mm + '/' + yyyy; useEffect(() => { setDate(today) }, []) const[newDay, setNewDay] = useState(dd) const changeToTomorrow = () => { const updateDay = newDay + 1 setNewDay(updateDay) setDate(updateDay + '/' + mm + '/' + yyyy) console.log(date) } const changeToYesterday = () => { const updateDay = newDay - 1 setNewDay(updateDay) setDate(updateDay + '/' + mm + '/' + yyyy) } return ( <div className="attendance-today-container"> <h1>Daily attendance</h1> <div className='change-date-container'> <div className='change-date'> <i class="fas fa-arrow-left" onClick={changeToYesterday}></i> <p>{date}</p> <i class="fas fa-arrow-right" onClick={changeToTomorrow}></i> </div> </div> </div> ); }Calcule primero la fecha actualizada en una nueva variable y luego configúrela en ambos estados:
const changeToTomorrow = () => { const updateDay = newDay + 1 setNewDay(updateDay) setDate(updateDay + '/' + mm + '/' + yyyy) console.log(date) } const changeToYesterday = () => { const updateDay = newDay - 1 setNewDay(updateDay) setDate(updateDay + '/' + mm + '/' + yyyy) }¿Puedo sugerir un enfoque diferente, así como una organización diferente del código?
const { useState, useEffect, useCallback } = React; // utility function (not part of the component) function formatDate(date, format = 'dd/mm/yyyy') { const addLeadingZero = num => { return num < 10 ? `0${num}` : num.toString(); } const dd = addLeadingZero(date.getDate()); const mm = addLeadingZero(date.getMonth() + 1); const yyyy = date.getFullYear().toString(); return format.replace('dd', dd).replace('mm', mm).replace('yyyy', yyyy); } // This constant is not strictly necessary but I think it makes the code more readable const ONE_DAY_MSEC = 86400000; // Component const MyComponent = () => { const [date, setDate] = useState(new Date()); // date as a date const [dispDate, setDispDate] = useState(formatDate(new Date())); // date as a formatted string useEffect(() => { setDispDate(formatDate(date)) }, [date, setDispDate]); const handleNextDayClick = useCallback(() => { setDate((current) => new Date(current.getTime() + ONE_DAY_MSEC)) }, [setDate]); const handlePrevDayClick = useCallback(() => { setDate((current) => new Date(current.getTime() - ONE_DAY_MSEC)) }, [setDate]); return ( <div> <div>Date: {dispDate}</div> <button onClick={handlePrevDayClick}>prev day</button> <button onClick={handleNextDayClick}>next day</button> </div> ); } ReactDOM.render(<MyComponent />, document.getElementById('App')); <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="App" />