1

I'm making a simple name and email list - by table in React. I want to fetch data from server, and next can add or remove persons dynamicly. This is my first steps with React, so I have a problem.

import React, { Component } from 'react';
import Form from "./Form";

class App extends Component {
    constructor(props) {
        super(props);

        this.state = {
            people: [],
        };

        this.addPerson = this.addPerson.bind(this);
    }

    addPerson(name, email) {
        this.state.people.push({name: name, email: email});
    }

    componentDidMount() {
        this.getPeople();
    }

    getPeople() {
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(response => response.json())
            .then(response => this.setState({people: response}))
            .catch(error => console.log(error));
    }


    render() {
        return (
            <div className='App'>
                <Form/>
                <table>
                    <thead>
                    <tr>
                        <th>LP</th>
                        <th>USER</th>
                        <th>EMAIL</th>
                    </tr>
                    </thead>
                    <tbody>
                    {this.state.people.map((person, index) => {
                        return (
                            <tr key={person.email}>
                                <th>{index + 1}</th>
                                <td>{person.name}</td>
                                <td>{person.email}</td>
                            </tr>
                        )

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

}

export default App;

and Form component:

import React, { Component } from 'react';

class Form extends Component {
    constructor() {
        super();

        this.state = {
            name: this.props.name,
            email: this.props.email
        };

        this.handleChange = this.handleChange.bind(this);
        this.addPerson = this.addPerson.bind(this);

    /*    this.formSubmit = this.formSubmit.bind(this); */
    }

    handleChange(e) {
        this.setState({[e.target.id]: e.target.value})
    }

    addPerson(name, email) {
        this.props.addPerson(name, email);
        this.setState({name: '', email: ''});
    }

    render() {
        return (
            <form>
                <input id='name' type='text' name={this.state.name} placeholder='Name...'/>
                <input id='email' type='text' email={this.state.email} placeholder='Email...'/>
                <input onClick={() => this.addPerson(this.state.name, this.state.email)} type='submit' value='submit'/>
            </form>
        )
    }

}

export default Form;

And now i want to can add data to table for form submit, or if I want, delete data for table. I got stuck in this moment...

2
  • What is not working? Commented Aug 19, 2018 at 15:25
  • TypeError: Cannot read property 'name' of undefined, Form component, line 8. For this moment. Commented Aug 19, 2018 at 15:29

2 Answers 2

3

I'd rewrite your code as follows.

I will make Form component as uncontrolled component. It means, the form inputs will maintain their own internal states when you change. There is no need to maintain two different sources of data. So I will rely on the parent component App state. I also add a form submit handler which will get the inputs values on submit, and then call the addPerson method from App to add the names to the people state maintained by root component App.

I added the deletePerson method to delete the people from the list. Here are the 2 components looks like.

deletePerson method here relies on the fact that people list will have person with uniq emails. As you also choose it as key props. But you can always change this criterion which will be easy if you understand the current flow of the code.

App.js

import React, { Component } from "react";
import Form from "./Form";

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      people: []
    };

    this.addPerson = this.addPerson.bind(this);
    this.deletePerson = this.deletePerson.bind(this);
  }

  addPerson(name, email) {
    this.setState(prevState => ({
      people: [...prevState.people, { name, email }]
    }));
  }

  componentDidMount() {
    this.getPeople();
  }

  getPeople() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(response => response.json())
      .then(response => this.setState({ people: response }))
      .catch(error => console.log(error));
  }

  deletePerson(email) {
    return () => {
      this.setState(prevState => ({
        people: prevState.people.filter(person => person.email !== email)
      }));
    };
  }

  render() {
    console.log(this.state);

    return (
      <div className="App">
        <Form addPerson={this.addPerson} />
        <table>
          <thead>
            <tr>
              <th>LP</th>
              <th>USER</th>
              <th>EMAIL</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {this.state.people.map((person, index) => {
              return (
                <tr key={person.email}>
                  <th>{index + 1}</th>
                  <td>{person.name}</td>
                  <td>{person.email}</td>
                  <td>
                    <button onClick={this.deletePerson(person.email)}>
                      Delete
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }
}

Form.js

import React, { Component } from "react";

class Form extends Component {
  constructor() {
    super();
    this.formSubmit = this.formSubmit.bind(this);
  }

  formSubmit(event) {
    event.preventDefault();
    const form = event.target;
    const email = form.elements["email"].value;
    const name = form.elements["name"].value;
    this.props.addPerson(name, email);
    form.reset();
  }

  render() {
    return (
      <form onSubmit={this.formSubmit}>
        <input
          id="name"
          type="text"
          defaultValue=""
          placeholder="Name..."
        />
        <input
          id="email"
          type="text"
          defaultValue=""
          placeholder="Email..."
        />
        <input type="submit" value="submit" />
      </form>
    );
  }
}

export default Form;

Please check Codesandbox demo.

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

1 Comment

Thank you so much!
0

You have to create a deletePerson function to your App component, and then pass deletePerson and addPerson as props to your Form component, like this:

<Form addPerson={this.addPerson} deletePerson={this.deletePerson} />

Then make use of them in your Form component.

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.