snazzyy
snazzyy

Reputation: 151

React/Hooks extra undefined field upon submission

I'm getting a really weird return error that on submission I randomly add an extra duplicate field somehow which is of course then undefined. The input value is also randomly copied from one of the other fields within the form.

const GameForm = () => {
    const url = 'http://localhost:6060/games'

    const handleInputChange = e => {
        const { name, value, year, rating, developer } = e.target
        setGameData({ ...gameData, [name]: value, [year]: value, [rating]: value, [developer]: value })
    }

    const onSubmit = (e) => {
        e.preventDefault()
        const { name, year, rating, developer } = gameData

        if (!name || !year || !rating || !developer) return

        console.log(gameData)

        axios
            .post(url, gameData)
            .then((res) => {
                setGameData(res)
            }).catch((error) => console.log(error))

    }

    const [gameData, setGameData] = useState({ name: '', year: 0, rating: '', developer: "" })

    return (
        <form onSubmit={onSubmit}>
            <label id="name" htmlFor="name">Name: </label>
            <input type="text" name="name" placeholder="Game title" onChange={handleInputChange} />
            <br />
            <label htmlFor="year">Year: </label>
            <input type="number" name="year" placeholder="Release year" onChange={handleInputChange} />
            <br />
            <label htmlFor="rating">Rating: </label>
            <input type="text" name="rating" placeholder="Age rating" onChange={handleInputChange} />
            <br />
            <label htmlFor="developer">Developer: </label>
            <input type="text" name="developer" placeholder="Developer" onChange={handleInputChange} />
            <br />
            <input type="submit" value="Submit"></input>
        </form>
    )
}

Console logged return: (I also get a 500 error obviously)

{name: "1", year: "1", rating: "1", developer: "1", undefined: "1"}

The undefined value is seemingly taken from any of the existing fields at random.

I feel like I am likely overlooking something obvious.

Upvotes: 0

Views: 390

Answers (1)

theJuls
theJuls

Reputation: 7460

You are mis-using e.target. It will not have all the properties that you try to destruct from it. From the ones you list in your example code, it will only have name and value, all the other ones (rating, year, developer) will be undefined as they are not part of the event's target property.

The reason you only get one undefined value in your state object is because it keeps overriding itself when you set your state.

The property from the event target you are trying to access is name, so in your case basically e.target.name

Anyway, with that in mind the fix for your app will be quite simple:

 const handleInputChange = e => {
        const { name, value } = e.target
        
       // Note: The name will hold whatever value of the name prop you put on your input.
       // When you are editing the input with the name prop set to name, it will be "name"
       // For the input with the name prop set to "year", it will be "year:
       // For the input with the name prop set to "developer" it will be "developer" and so on.
        setGameData({ ...gameData, [name]: value })
    }

Here is a demo for you with the fix:

const App = () => {
    const [gameData, setGameData] = React.useState({ name: '', year: 0, rating: '', developer: "" })


    const handleInputChange = e => {
        const { name, value } = e.target
        
        setGameData({ ...gameData, [name]: value })
    }

  return (
  <div>
              <label id="name" htmlFor="name">Name: </label>
 <input type="text" name="name" placeholder="Game title" onChange={handleInputChange} />
            <br />
            <label htmlFor="year">Year: </label>
            <input type="number" name="year" placeholder="Release year" onChange={handleInputChange} />
            <br />
            <label htmlFor="rating">Rating: </label>
            <input type="text" name="rating" placeholder="Age rating" onChange={handleInputChange} />
            <br />
            <label htmlFor="developer">Developer: </label>
            <input type="text" name="developer" placeholder="Developer" onChange={handleInputChange} />
            <br />
                <button onClick={() => console.warn('GAME DATA OBJECT', gameData)}>Click</button>

  </div>
  )
}


ReactDOM.render(
    <App />,
    document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Upvotes: 1

Related Questions