0

I'm trying to make a form where I can enter three values for a game (title, rating, and price) and save those values on submit and show the list underneath in a table. I am new to react and I got it working by using ref but I'm not sure if this is best practice. While googling for a solution, I saw many people use onChange to save the state as it's being typed even when there is a submit button. This is what I did but im not sure if this is best practice. Can I get some feedback? Thank you!

class App extends Component {

state = {
    games: [{title:"Mario Kart", rating:7.4,price:"$45"}]        
};   

handleSubmitButton = (e) => {
    e.preventDefault();
    this.setState(prevState => ({
        games: [...prevState.games, {
        title: this.refs.title.value,
        rating: this.refs.rating.value,
        price: this.refs.price.value
        }] 
    }));
}

render () {
return (
<div>
 <form onSubmit={this.handleSubmitButton}>
    <label>
        Game Name
        <input type="text" id="name-input" ref="title"/>
    </label>
    <label>
        Rating
        <input type="text" id="ratings-input" ref="rating"/>
    </label>
    <label>
        Price
        <input type="text" id="price-input" ref="price"/>   
    </label>
    <button type="submit" id="submit-button">Submit</button>
 </form>
 <label>
    Search
    <input type="text" id="search-input"/>
 </label>
  <table id="directory-table">
    <tr>
        <th>Name</th>
        <th>Ratings</th>
        <th>Duration</th>
    </tr>
    {this.state.games.map(game => {
        return (
           <tr>
             <th>{game.title}</th>
             <th>{game.rating}</th>
             <th>{game.price}</th>
           </tr>
    )

    })}
    </table>
  </div>
);

} }

2 Answers 2

1

I think as you mentioned the preferred way is to use onChange to update the state for each controlled input and then set the value of the input to value in your state. Then once you hit submit you trigger a function that can maybe validate your inputs before posting the values to your endpoint.

In your example you could set a boolean value in your state once each input is valid that you use as a condition in your table output:

{this.state.formValid && this.state.games.map(games => ...

One way of achieving this is that you could use an onChange handler to push the current value into a temporary state slot, say your input has an id of 'title', then use this.setState({ [event.target.id]: event.target.value }) then in your submit handler build an object from the temporary values to push into your games array and finally clear the title, rating and price values in state?

This is a bit of rubbish example of what I mean although I have done it using hooks and have some repetition with the useState values that could be done better with useReducer for example: https://codesandbox.io/s/peaceful-moore-jrjpg

Sign up to request clarification or add additional context in comments.

Comments

1

Try Use Controlled Component as input and also use destructuring is the best practice. you can read about controlled component here https://www.robinwieruch.de/react-controlled-components/ also read about list and keys because you made a mistake at when you mapped the values to print table rows https://reactjs.org/docs/lists-and-keys.html

Try following code

import React, { Component } from 'react';
import './App.css';
class App extends Component {
    state = {
        title: "",
        rating: "",
        price: "",
        games: [{ title: "Mario Kart", rating: 7.4, price: "$45" }]
    };

    handleSubmitButton = (e) => {

        e.preventDefault();
        const { title, rating, price } = this.state;
        this.setState(prevState => ({
            games: [...prevState.games, { title, rating, price }]
        }));
    }

    handleChange = (evt) => {
        console.log(evt.target)
        this.setState({ [evt.target.name]: evt.target.value });
    }

    render() {
        const { title, rating, price } = this.state
        return (
            <div>
                <form onSubmit={this.handleSubmitButton}>
                    <label>
                        Game Name
                      <input
                            type="text"
                            id="name-input"
                            name="title"
                            value={title}
                            onChange={(evt) => this.handleChange(evt)}
                        />
                    </label>
                    <label>
                        Rating
                    <input

                            type="text"
                            id="ratings-input"
                            name="rating"
                            value={rating}
                            onChange={(evt) => this.handleChange(evt)}
                        />
                    </label>
                    <label>
                        Price
                    <input
                            type="text"
                            id="price-input"
                            name="price"
                            value={price}
                            onChange={(evt) => this.handleChange(evt)}
                        />
                    </label>
                    <button type="submit" id="submit-button">Submit</button>
                </form>
                <label>
                    Search
                <input type="text"
                        id="search-input" />
                </label>
                <table id="directory-table">
                    <tbody>
                        <tr>
                            <th>Name</th>
                            <th>Ratings</th>
                            <th>Duration</th>
                        </tr>

                        {this.state.games.map((game,index) => {
                            return (
                                <tr key={index}>
                                    <th>{game.title}</th>
                                    <th>{game.rating}</th>
                                    <th>{game.price}</th>
                                </tr>
                            )

                        })}
                    </tbody>
                </table>
            </div>
        );
    }
}

export default App;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.