I'm trying to pass a Date object as payload to my formSlice but I keep getting the Error that Objects are not valid as React child or Invalid time Range when I pass the date as string with ToString() or ToLocaleString(). I have read that it's better to have only primitive types for state in Redux.
Here is how my formSlice looks like in Redux store:
import { createSlice } from "@reduxjs/toolkit";
const formSlice = createSlice({
name: 'form',
initialState: {
firstName : '',
lastName : '',
dateOfBirth : '',
userName : '',
password : ''
},
reducers: {
changeFirstName(state, action){
state.firstName = action.payload;
},
changeLastName(state, action){
state.lastName = action.payload;
},
changeDateOfBirth(state, action){
state.dateOfBirth = action.payload
},
changeUsername(state, action){
state.userName = action.payload
},
changePassword(state, action){
state.password = action.payload
}
}
});
export const {
changeFirstName,
changeLastName,
changeDateOfBirth,
changeUsername,
changePassword
} = formSlice.actions;
export const formReducer = formSlice.reducer;
This is my form component:
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import ReactDOM from "react-dom";
import DatePicker from "react-datepicker";
import {
addCustomer,
changeFirstName,
changeLastName,
changeDateOfBirth,
changeUsername,
changePassword
} from '../store/index.js';
import 'react-datepicker/dist/react-datepicker.css';
function Form ({ onClose, children, actionBar }) {
useEffect(() => {
document.body.classList.add('overflow-hidden');
return () => {
document.body.classList.remove('overflow-hidden')
};
},[]);
const form = useSelector((state) => {
return state.form;
});
const dispatch = useDispatch();
const handleFirstNameChange = (event) => {
dispatch(changeFirstName(event.target.value));
}
const handleLastNameChange = (event) => {
dispatch(changeLastName(event.target.value));
}
const handleUserNameChange = (event) => {
dispatch(changeUsername(event.target.value));
}
const handlePasswordChange = (event) => {
dispatch(changePassword(event.target.value));
}
const handleDateOfBirthChange = (date) => {
//let formattedDate = formatDate(date);
//console.log(formattedDate);
dispatch(changeDateOfBirth(date));
}
const handleSubmit = (event) => {
event.preventDefault();
dispatch(addCustomer(form))
onClose();
}
return ReactDOM.createPortal(
<div className="fixed inset-0 flex items-center justify-center" onClick={onClose}>
<form
onClick={(e) => e.stopPropagation()}
className="bg-white shadow-md rounded-md p-8 w-full max-w-md"
onSubmit={handleSubmit}
>
<h2 className="text-2xl font-bold mb-4">Add Customer</h2>
<div className="mb-4">
<label
htmlFor="firstName"
className="block text-sm font-medium leading-6 text-gray-900 mb-1"
>
First Name
</label>
<input
type="text"
value={form.firstName}
onChange={handleFirstNameChange}
name="firstName"
id="firstName"
className="mb-1 block w-full border-2 border-blue-300 bg-blue-100 rounded-md py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
/>
</div>
<div className="mb-4">
<label
htmlFor="lastName"
className="block text-sm font-medium leading-6 text-gray-900 mb-1"
>
Last Name
</label>
<input
type="text"
value={form.lastName}
onChange={handleLastNameChange}
name="lastName"
id="lastName"
className="block w-full border-2 border-blue-300 bg-blue-100 rounded-md py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6 mb-1"
/>
</div>
<div className="mb-4">
<label
htmlFor="dateOfBirth"
className="block text-sm font-medium leading-6 text-gray-900 mb-1"
>
Date of Birth
</label>
<DatePicker
placeholderText="YYYY/MM/DD"
selected={form.dateOfBirth}
onChange={handleDateOfBirthChange}
dateFormat="yyyy-MM-dd"
className="block w-full border-2 border-blue-500 bg-blue-100 rounded-md py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
/>
</div>
<div className="mb-4">
<label
htmlFor="userName"
className="block text-sm font-medium leading-6 text-gray-900 mb-1"
>
User Name
</label>
<input
type="text"
value={form.userName}
onChange={handleUserNameChange}
name="userName"
id="userName"
className="block w-full border-2 border-blue-300 bg-blue-100 rounded-md py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6 mb-1"
/>
</div>
<div className="mb-4">
<label
htmlFor="password"
className="block text-sm font-medium leading-6 text-gray-900 mb-1"
>
Password
</label>
<input
type="text"
value={form.password}
onChange={handlePasswordChange}
name="password"
id="password"
className="block w-full border-2 border-blue-300 bg-blue-100 rounded-md py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6 mb-1"
/>
</div>
<div className="mt-4">
<button
type="submit"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Submit
</button>
</div>
</form>
</div>,
document.querySelector('.modal-container')
);
}
I have tried to convert date to string in selected prop but still getting an error.
<DatePicker
placeholderText="YYYY/MM/DD"
selected={form.dateOfBirth.toString()}
onChange={handleDateOfBirthChange}
dateFormat="yyyy-MM-dd"
/>
You can serialize, e.g. stringify, the
dateOfBirthvalue when dispatching to the store. You'll then need to de-serializedateOfBirthwhen reading it back out of the store to be passed to theDatePickercomponent.Example:
Demo