Home > Blockchain >  my onChange event is not working on input elements
my onChange event is not working on input elements

Time:12-31

I have a component called Resume.js in which I define a function called handleChange which takes in an input paramater and based on that input value it changes my global state.

Resume.js:

import React from 'react'
import PersonalInfo from './PersonalInfo'
import { useState } from 'react'

const Resume = () => {

    const [resumeStates, setResumeStates] = useState({
        step: 1,
        firstName: '',
        lastName: '',
        email: '',
        phone: '',
        address: '',
        linkedIn: '',
        jobTitle: '',
        city: '',
        employer: '',
        startDate:'',
        endDate: '',
        responsibilities: ''
    })

    const nextStep = () => {
        const {step} = resumeStates
        setResumeStates({
            step: step 1
        })
    }

    const prevStep = () => {
        const {step} = resumeStates
        setResumeStates({
            step: step-1
        })
    }

    const handleChange = input => e => {
        setResumeStates({[input]: e.target.value})
    }

I am passing this handleChange function as props to a component called PersonalInfo.js as such:

return (
                <PersonalInfo nextStep={nextStep} handleChange={handleChange} values={values}/>
            )

In PersonalInfo.js I am using that prop as an onChange for my input fields:

import React from 'react'

const PersonalInfo = ({nextStep, handleChange, values}) => {

    const continue_step = (e) => {
        e.preventDefault()
        nextStep()
    }

    return (
        <div>
            <div className="container-lg w-50 rounded p-3 mt-5 ">
                <h2 className="mb-3">Personal Details</h2>
                <form>
                    <div className="mb-3 row">
                        <div className="form-group">
                            <label htmlFor="fname" className="form-label">First Name:</label>
                            <input type="text" className="form-control" id="fname" value={values.firstName} onChange={() => handleChange('firstName')}/>
                            <div className={`text-danger fw-bold ${alert ? 'hidden': ''}`}>This is a required field</div>
                        </div>
                    </div>
                    <div className="mb-3 row">
                        <div className="form-group">
                            <label htmlFor="lname" className="form-label">Last Name:</label>
                            <input type="text" className="form-control" id="lname" value={values.lastName} onChange={() => handleChange('lastName')}/>
                            <div className={`text-danger fw-bold ${alert ? 'hidden': ''}`}>This is a required field</div>
                        </div>
                    </div>

But my onChange for my input fields is not working as I cannot type anything in my input as a results my states do not change.

I would appreciate any kind of help...

Thank you for your time and attention.

CodePudding user response:

You're passing something called values to the component for the input values, but I don't see it defined anywhere. It looks like it the values should just be the state object, so pass that:

<PersonalInfo nextStep={nextStep} handleChange={handleChange} values={resumeStates}/>
                                                                      ^-- here --^

Additionally, you're removing all of your state values any time you set one:

setResumeStates({[input]: e.target.value})

Unlike the setState operation in older class-based components, the set operation in the useState hook does not determine the difference for you and only update the new parts. It replaces the state with the new state entirely. Make sure you keep the existing state when updating it:

setResumeStates({ ...resumeStates, [input]: e.target.value })

The same will need to be done for your other state updates as well.

And finally, you're not passing the actual change event to the change handler. Only the title. You can pass the change event to the function returned by the function of the change handler:

onChange={e => handleChange('firstName')(e)}

Or [potentially] more simply:

onChange={handleChange('firstName')}

This might be getting a little confusing though and is likely to result in bugs. (After all, it already has.) Instead of the function within a function, just accept both arguments in the handleChange function:

const handleChange = (input, e) => {
  setResumeStates({...resumeStates, [input]: e.target.value})
}

And pass them both:

onChange={e => handleChange('firstName', e)}

As an aside, to help you with design-time validation of what's being passed to what functions, you might try making use of TypeScript in your React development.

CodePudding user response:

Ok, you're doing a funception here.

    const handleChange = input => e => {
        setResumeStates({[input]: e.target.value})
    }

This is a "function" that returns a "function that updates state". What you need is to bind a "function that updates state" to "onChange"


So you can try one of these.

First way, just declare a function that receive input event normally.

const handleChange = e => {
   setResumeStates({[e.target.name]: e.target.value})
}

<input
  type="text"
  name="firstName"
  value={values.firstName}
  onChange={handleChange}
/>

or if you are feeling func-ky and wanna do func-ception. You can bind onChange with handleChange('firstName'). Note that "handleChange('firstName')" will return a function that accept "e" as parameter.

const handleChange = input => e => {
   setResumeStates({[input]: e.target.value})
}

<input
  type="text"
  value={values.firstName}
  onChange={handleChange('firstName')}
/>
  • Related