I am using React Context to create a multistep form, the form must keep the selection when the user clicks the next or previous step. I am using the below code and it’s working fine until I reach the stage to add multiple features using the checkbox, once items are checked, user can go to the previous step to edit and press next to go to the next stage where checked checkboxes must remain checked. I cannot figure out how to push each checkbox value to the features array and remove the item from array when the user uncheck. The important part is to retain the selected despite user go to previous or next step.
Context Provider
import React, { useEffect, useState, createContext } from 'react' const carSpecs = { make: '', features: [],model: '',serviceHistory: false, warranty: false, trim: '', bodyType: '', transmission:'' } export const UsedCarListingContext = createContext({}) export function GlobalUsedCarListingProvider (props) { const [usedCar, setUsedCar] = useState(carSpecs) useEffect(() => {}, [usedCar]) return ( <UsedCarListingContext.Provider value={[usedCar, setUsedCar]} > {props.children} </UsedCarListingContext.Provider> ) }
Car Details Component
export const UsedCarAdDetails = () => { const [usedCar, setUsedCar] = useContext(UsedCarListingContext) const changeHandler = (e) => { const {name, value} = e.target setUsedCar({ ...usedCar, [name]: value }) } const handleChange = ({target: {name, checked}}) => { setUsedCar({ ...usedCar, [name]: checked }) } return ( <div className="container-1100 bg-white shadow-nav-bar w-full h-52 pt-12"> <NavLink to={'/'} className='landing-nav-logo'> <img className='mr-20 mt-4 w-66 ottobay-logo-center' src={OttobayGray} alt={'logo'} /> </NavLink> </div> <div className="container-1050 mg-0auto flex justify-between mt-48"> <div className='container-700 p-20'> <form> <div className='ad-listing-input-wrapper mb-16-mobile mb-16 w-full-mobile flex items-center'> <div className='ad-label-container'> <label className="listing-input-label font-semibold mr-40" htmlFor="videoLink">History: </label> </div> <div className="ad-input-group-container"> <div className='checkbox-group-container'> <CheckboxWithImage onChange={handleChange} name={'serviceHistory'} checked={usedCar.serviceHistory} label={'Service History'} icon={<GiAutoRepair/>} checkboxTitleClass={'historyCB'} /> <CheckboxWithImage onChange={handleChange} name={'warranty'} checked={usedCar.warranty} label={'Warranty'} icon={<AiOutlineFileProtect/>} checkboxTitleClass={'historyCB'} /> </div> </div> </div> <div> <div className='checkbox-group-wrapper'> {carFeatures.map(item => ( <div className='feature-item'> <Checkbox label={item.name} onChange={handleFeaturesChange} checked={usedCar && usedCar.features.some(val => val === item.id)} value={item.id} /> </div> ))} </div> </div> <div className="error-container"></div> </div> <div className="car-basic-submission-container"> <div> </div> <button type='submit' className='search-button bg-button-primary text-white font-semibold rounded-4'> Next Step</button> </div> </form> </div> ) }
Advertisement
Answer
You seem to be calling a non existent function handleFeaturesChange
in you feature-item checkbox.
Anyway, something like this should work:
const handleFeaturesChange = ({target: {value, checked}}) => { setUsedCar({ ...usedCar, features: checked ? [ ...usedCar.features, value, // add the value to previously selected features ] : usedCar.features.filter(val => val !== value) // remove the value }) }
You could potentially replace the value with name string but then you’d need to update the condition in the checked
param of the Checkbox to compare it with the name instead.