Search code examples
javascriptreactjstypeerrorcodesandbox

The code is working fine in codeSandbox, But showing error while doing in the IDE as "can't define property "email": Object is not extensible"


I am trying to implement a simple code in react.js which user can input the data using form and unless the page is refreshed the data will show in the table.

I have implemented a code in Code Sandbox and it worked as expected. Then I copied that code and used it in the IDE. Now the same code is showing error as ==> "TypeError: can't define property "email": Object is not extensible". (I am using intellij IDE ultimate edition)

This is the link for sandbox => Link for the code in sandbox

The code it self if the sand box is not working ==>

import React, {Component} from "react";

class CustomDetails extends Component {

constructor(props) {
    super(props);
    this.state = {
        items: [{email: '', country: '', new_case: '', total_case: '', total_death: ''}],
        message: ''
    }
    this.newData = React.createRef();
    this.addForm = React.createRef();

}

addData(e) {
    e.preventDefault();
    const {items} = this.state;
    
    const newData = () => ({
        email:this.addForm.email.value,
        country:this.addForm.country.value,
        new_case:this.addForm.new_case.value,
        total_case:this.addForm.total_case.value,
        total_death:this.addForm.total_death.value
    })
    const isOnTheList = items.includes(newData.country);

    if (isOnTheList) {
        this.setState(({
            message: 'This country details are already added.'
        }))
    } else {
        this.setState({
            items: [...this.state.items, newData()],
        })
    }
    this.addForm.reset();
}




render() {
    const {items, message}=this.state;
    return (
        <div>
            <div>
            
                <div>
                    <form ref={input => this.addForm = input} onSubmit={(e) => {
                        this.addData(e)
                    }}>
         
                            <label>User Email :</label><br/>
                            <input required ref={input => this.newData["email"] = input} name="email" value={this.state.items.email}
                                   type="email"
                                   placeholder="Enter email"/><br></br>

                           
                                <label>Country :</label><br/>
                                <input required ref={input => this.newData["country"] = input} name="country" value={this.state.items.country}
                                       type="text"
                                       placeholder="Enter country"/><br></br>
                           

                            
                                <label>New Cases :</label><br/>
                                <input required ref={input => this.newData["new_case"] = input}
                                name="new_case"
                                       value={this.state.items.new_case} type="text"
                                       placeholder="Enter no of new cases"/><br></br>
                           

                           
                                <label>Total cases :</label><br/>
                                <input required ref={input => this.newData["total_case"] = input}
                                name="total_case"
                                       value={this.state.items.total_case} type="text"
                                       placeholder="Enter no of total cases"/><br></br>
                           

                           
                                <label>Total death :</label><br/>
                                <input required ref={input => this.newData["total_death"] = input}
                                name="total_death"
                                       value={this.state.items.total_death} type="text"
                                       placeholder="Enter no of total deaths"/><br></br>
                            

                            <button variant="primary" type="submit">
                                Submit</button><br></br>
                       
                    </form>

                </div>
                <div>
                    
                   
                    {
                        message !== '' && <p>{this.setState.message}</p>
                    }
                    <table striped="true" bordered="true" hover="true">
                        <thead>
                        <tr>
                            <th>Email</th>
                            <th>Country</th>
                            <th>New cases</th>
                            <th>Total cases</th>
                            <th>Total deaths</th>
                        </tr>
                        </thead>
                        <tbody>
                        {items.map((item,index) => {
                            return (
                                <tr key={index}>

                                    <td>{item.email}</td>
                                    <td>{item.country}</td>
                                    <td>{item.new_case}</td>
                                    <td>{item.total_case}</td>
                                    <td>{item.total_death}</td>
                                </tr>
                            )
                        })}
                        </tbody>
                    </table>
                </div>
              
            </div>
        </div>
    )
}}export default CustomDetails;

The output in sandbox --> Sand box output

The error while running it in IDE --> ide error


Solution

  • There really isn't a point to using React refs in this case as you can easily access the field values from the form's onSubmit event object.

    1. Initial state should be an empty array.

      this.state = {
        items: [],
      };
      
    2. The addData callback needs this of the class bound to it.

    3. addData should access the form field values from the onSubmit event object. The newData should be an object of the form field values you want to push into your items state array. Use a functional state update to update from the previous state. When searching the items array for existing entries you need to use an array function that allows examining object properties as Array.prototype.includes really only check reference equality, you want to search for an item that has a matching country property using Array.prototype.some to return a boolean.

      addData = (e) => {
        e.preventDefault();
        const { items } = this.state;
      
        const newData = {
          email: e.target.email.value,
          country: e.target.country.value,
          new_case: e.target.new_case.value,
          total_case: e.target.total_case.value,
          total_death: e.target.total_death.value
        };
      
        const isOnTheList = items.some(item => item.country === newData.country);
      
        if (isOnTheList) {
          this.setState({
            message: "This country details are already added."
          });
        } else {
          this.setState((prevState) => ({
            items: [...prevState.items, newData]
          }));
        }
        e.target.reset();
      };
      
    4. Since you've uncontrolled inputs you should remove the old "legacy" style ref attachments and value prop. Example:

      <input
        required
        name="email"
        type="email"
        placeholder="Enter email"
      />
      
    5. You've a typo when trying to render an error message, {message !== "" && <p>{this.setState.message}</p>}, it should be {message !== "" && <p>{this.state.message}</p>}.

    Demo

    Edit the-code-is-working-fine-in-codesandbox-but-showing-error-while-doing-in-the-id

    Full code:

    class CustomDetails extends Component {
      constructor(props) {
        super(props);
        this.state = {
          items: [],
          message: ""
        };
      }
    
      addData = (e) => {
        e.preventDefault();
        const { items } = this.state;
    
        const newData = {
          email: e.target.email.value,
          country: e.target.country.value,
          new_case: e.target.new_case.value,
          total_case: e.target.total_case.value,
          total_death: e.target.total_death.value
        };
        const isOnTheList = items.includes(newData.country);
    
        if (isOnTheList) {
          this.setState({
            message: "This country details are already added."
          });
        } else {
          this.setState((prevState) => ({
            items: [...prevState.items, newData]
          }));
        }
        e.target.reset();
      };
    
      render() {
        const { items, message } = this.state;
        return (
          <div>
            <div>
              <div>
                <form onSubmit={this.addData}>
                  <label>User Email :</label>
                  <br />
                  <input
                    required
                    name="email"
                    type="email"
                    placeholder="Enter email"
                  />
                  <br></br>
    
                  <label>Country :</label>
                  <br />
                  <input
                    required
                    name="country"
                    type="text"
                    placeholder="Enter country"
                  />
                  <br></br>
    
                  <label>New Cases :</label>
                  <br />
                  <input
                    required
                    name="new_case"
                    type="text"
                    placeholder="Enter no of new cases"
                  />
                  <br></br>
    
                  <label>Total cases :</label>
                  <br />
                  <input
                    required
                    name="total_case"
                    type="text"
                    placeholder="Enter no of total cases"
                  />
                  <br></br>
    
                  <label>Total death :</label>
                  <br />
                  <input
                    required
                    name="total_death"
                    type="text"
                    placeholder="Enter no of total deaths"
                  />
                  <br></br>
    
                  <button variant="primary" type="submit">
                    Submit
                  </button>
                  <br></br>
                </form>
              </div>
              <div>
                {message !== "" && <p>{this.state.message}</p>}
                <table striped="true" bordered="true" hover="true">
                  <thead>
                    <tr>
                      <th>Email</th>
                      <th>Country</th>
                      <th>New cases</th>
                      <th>Total cases</th>
                      <th>Total deaths</th>
                    </tr>
                  </thead>
                  <tbody>
                    {items.map((item, index) => {
                      return (
                        <tr key={index}>
                          <td>{item.email}</td>
                          <td>{item.country}</td>
                          <td>{item.new_case}</td>
                          <td>{item.total_case}</td>
                          <td>{item.total_death}</td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        );
      }
    }