I am building a React component that allows a user to click a button to move the date forward by 10 days. My code seems to update the state 'selectedDate' but the component does not re-render. I have tried swapping the state to a number (e.g 500) and having it increment by 1 each time and that does make the component re-render. For some reason, it won't re-render when a state is a Date object.
import React from 'react';
import { useState, useEffect } from 'react';
const BrowserHeader = () => {
const today = new Date();
const [selectedDate, setSelectedDate] = useState(today);
const onButtonClick = () => {
const currentDate = selectedDate;
currentDate.setDate(currentDate.getDate() 10);
setSelectedDate(currentDate);
console.log('selectedDate is now:', selectedDate);
};
return (
<div className='browser-header'>
<button>
<i className="fas fa-fast-backward"></i>
</button>
<form>
<label>Date:</label>
<input
value={selectedDate}
onChange={e => setSelectedDate(e.target.value)}
/>
<button><i className="fas fa-sync-alt"></i></button>
</form>
<button onClick={onButtonClick}>
<i className="fas fa-fast-forward" ></i>
</button>
</div>
);
};
export default BrowserHeader;
CodePudding user response:
Change your onClick handler like below. Instead of updating the currentDate
. You need to create a new date then change it and set it as the current state. Otherwise react will ignore the rerender considering the referential equality.
const onButtonClick = () => {
// create a new date object using prevoius state
const newDate = new Date(selectedDate.getDate());
// update it
newDate.setDate(selectedDate.getDate() 10);
// set it as the new state
setSelectedDate(newDate);
};
By adding a simple value check function to your current implementation, You can see that the state has actually updated to date ahead of 10 days but rendering has not happened => https://codesandbox.io/s/elated-pond-g46mm?file=/src/App.js
NOTE: You will notice the same issue with any mutable data structures like Array, Date, Object, ...etc.
CodePudding user response:
I read this and realised where things were going wrong... How to clone a Date object?
Essentially, I was mutating state the incorrect way when I duplicated the date object.
CodePudding user response:
You create a new Date object from the existing date it'll rerender the component.
const today = new Date();
const [selectedDate, setSelectedDate] = useState(today);
const onButtonClick = () => {
const currentDate = new Date(selectedDate); // update here
currentDate.setDate(currentDate.getDate() 10);
setSelectedDate(currentDate);
console.log("selectedDate is now:", selectedDate);
};