最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - react childparent component - onChange event just takes one character and not retaining value - Stack Overflow

programmeradmin0浏览0评论

In ReactJS, in my child ponent, onChange() event on a input > text just takes one value and not retaining previous values on every keypress.

I am trying to capture the inputs in a child form and wants to transfer it to parent. Actually I am trying to reuse the child form for Create & Edit pages.

My full codesandbox is here

Child Component

    import React, { Component } from "react";
    import { Form } from "react-bootstrap";

    export default class EmployeeForm extends Component {
      constructor(props) {
        super(props);
        console.log("this.props.employee ", this.props.employee);
      }

      /** Generic handle change events for all fields */
      handleChange = e => {
        this.props.employee[e.target.id] = e.target.value;
        console.log(e.target.value);
      };

      //   handleChange = (key, e) => {
      //     e.preventDefault();
      //     console.log(key);
      //     console.log(e.target.value);
      //     this.props.employee[key] = e.target.value;
      //   };

      render() {
        const { employee } = this.props;
        console.log("ef render ", employee.firstName);

        return (
          <div>
            <Form.Group controlId="firstName">
              <Form.Label>First name</Form.Label>
              <Form.Control
                type="text"
                value={employee.firstName}
                onChange={this.handleChange}
                placeholder="Enter first name"
              />
            </Form.Group>
            <Form.Group controlId="lastname">
              <Form.Label>Last name</Form.Label>
              <Form.Control
                type="text"
                value={employee.lastName}
                onChange={this.handleChange}
                placeholder="Enter last name"
              />
            </Form.Group>
            <Form.Group controlId="birthDate">
              <Form.Label>Date of birth</Form.Label>
              <Form.Control
                type="date"
                value={employee.birthDate}
                onChange={this.handleChange}
              />
            </Form.Group>
            <Form.Group controlId="hireDate">
              <Form.Label>Date of hire</Form.Label>
              <Form.Control
                type="date"
                value={employee.hireDate}
                onChange={this.handleChange}
              />
            </Form.Group>
            <Form.Group controlId="gender">
              <Form.Label>Gender</Form.Label>
              <Form.Control
                as="select"
                value={employee.gender}
                onChange={this.handleChange}
              >
                <option value="">Please select</option>
                <option value="F">Female</option>
                <option value="M">Male</option>
              </Form.Control>
            </Form.Group>
          </div>
        );
      }
    }

Parent Component

    import React from "react";
    import { Alert, Form, Col, Row, Button, Card } from "react-bootstrap";
    import EmployeeForm from "./EmployeeForm";
    import EmployeeService from "./services/EmployeeService";

    export default class CreateEmployee extends React.Component {
      constructor() {
        super();
        this.employeeService = new EmployeeService();
        this.state = {
          employee: {
            firstName: "",
            lastName: "",
            birthDate: "",
            hireDate: "",
            gender: ""
          }
        };
      }

      save = () => {
        console.log(this.state.values);
        this.employeeService
          .createEmployee(this.state.values)
          .then(result => {
            this.setState({ error: null });
          })
          .catch(err => {
            console.log(err);
            this.setState({ error: err });
          });
      };

      render() {
        console.log("reder : ", this.state.employee);

        return (
          <div>
            <Form>
              <Alert variant="primary">Employee</Alert>

              <Card style={{ width: "500px" }}>
                <Card.Header>Create Employee</Card.Header>
                <Card.Body>
                  <EmployeeForm employee={this.state.employee} />
                  <Row>
                    <Col>
                      <Button variant="primary" type="button" onClick={this.save}>
                        Create
                      </Button>
                    </Col>
                  </Row>
                </Card.Body>
              </Card>
            </Form>
          </div>
        );
      }
    }

In ReactJS, in my child ponent, onChange() event on a input > text just takes one value and not retaining previous values on every keypress.

I am trying to capture the inputs in a child form and wants to transfer it to parent. Actually I am trying to reuse the child form for Create & Edit pages.

My full codesandbox is here https://codesandbox.io/embed/sleepy-stallman-fbyhh?fontsize=14

Child Component

    import React, { Component } from "react";
    import { Form } from "react-bootstrap";

    export default class EmployeeForm extends Component {
      constructor(props) {
        super(props);
        console.log("this.props.employee ", this.props.employee);
      }

      /** Generic handle change events for all fields */
      handleChange = e => {
        this.props.employee[e.target.id] = e.target.value;
        console.log(e.target.value);
      };

      //   handleChange = (key, e) => {
      //     e.preventDefault();
      //     console.log(key);
      //     console.log(e.target.value);
      //     this.props.employee[key] = e.target.value;
      //   };

      render() {
        const { employee } = this.props;
        console.log("ef render ", employee.firstName);

        return (
          <div>
            <Form.Group controlId="firstName">
              <Form.Label>First name</Form.Label>
              <Form.Control
                type="text"
                value={employee.firstName}
                onChange={this.handleChange}
                placeholder="Enter first name"
              />
            </Form.Group>
            <Form.Group controlId="lastname">
              <Form.Label>Last name</Form.Label>
              <Form.Control
                type="text"
                value={employee.lastName}
                onChange={this.handleChange}
                placeholder="Enter last name"
              />
            </Form.Group>
            <Form.Group controlId="birthDate">
              <Form.Label>Date of birth</Form.Label>
              <Form.Control
                type="date"
                value={employee.birthDate}
                onChange={this.handleChange}
              />
            </Form.Group>
            <Form.Group controlId="hireDate">
              <Form.Label>Date of hire</Form.Label>
              <Form.Control
                type="date"
                value={employee.hireDate}
                onChange={this.handleChange}
              />
            </Form.Group>
            <Form.Group controlId="gender">
              <Form.Label>Gender</Form.Label>
              <Form.Control
                as="select"
                value={employee.gender}
                onChange={this.handleChange}
              >
                <option value="">Please select</option>
                <option value="F">Female</option>
                <option value="M">Male</option>
              </Form.Control>
            </Form.Group>
          </div>
        );
      }
    }

Parent Component

    import React from "react";
    import { Alert, Form, Col, Row, Button, Card } from "react-bootstrap";
    import EmployeeForm from "./EmployeeForm";
    import EmployeeService from "./services/EmployeeService";

    export default class CreateEmployee extends React.Component {
      constructor() {
        super();
        this.employeeService = new EmployeeService();
        this.state = {
          employee: {
            firstName: "",
            lastName: "",
            birthDate: "",
            hireDate: "",
            gender: ""
          }
        };
      }

      save = () => {
        console.log(this.state.values);
        this.employeeService
          .createEmployee(this.state.values)
          .then(result => {
            this.setState({ error: null });
          })
          .catch(err => {
            console.log(err);
            this.setState({ error: err });
          });
      };

      render() {
        console.log("reder : ", this.state.employee);

        return (
          <div>
            <Form>
              <Alert variant="primary">Employee</Alert>

              <Card style={{ width: "500px" }}>
                <Card.Header>Create Employee</Card.Header>
                <Card.Body>
                  <EmployeeForm employee={this.state.employee} />
                  <Row>
                    <Col>
                      <Button variant="primary" type="button" onClick={this.save}>
                        Create
                      </Button>
                    </Col>
                  </Row>
                </Card.Body>
              </Card>
            </Form>
          </div>
        );
      }
    }
Share Improve this question edited Sep 14, 2019 at 17:48 Jay asked Sep 14, 2019 at 17:32 JayJay 9,50914 gold badges62 silver badges100 bronze badges 2
  • 2 You are mutating state: this.props.employee[e.target.id] = e.target.value; pass a change function from parent to child that does a setState without mutating. – HMR Commented Sep 14, 2019 at 17:34
  • Thanks, its actual child to parent munication. Once the user enters all data in the child form I want to transfer to the parent. – Jay Commented Sep 14, 2019 at 17:40
Add a ment  | 

3 Answers 3

Reset to default 2

So I went through the code on codesandbox and made the following changes - the obvious changes have ments on-top: You can check them out here - https://codesandbox.io/s/react-parent-child-1fif1?fontsize=14

You should not do the following:

  • Mutate state directly

  • Try to mutate a state in a parent ponent from child ponent's props

EmployeeForm.js - Child ponent

import React, { Component } from "react";
import { Form } from "react-bootstrap";

export default class EmployeeForm extends Component {
  constructor(props) {
    super(props);
  }
// create a handleChangle method here, that calls the handleChange from props
// So you can update the state in CreateEmployee with values from the form

  handleChange = e => {
    this.props.handleChange(e)
  };

  render() {
    const { employee } = this.props;
    // console.log("ef render ", employee.firstName);

    return (
      <div>
        <Form.Group controlId="firstName">
          <Form.Label>First name</Form.Label>
          <Form.Control
            type="text"
            value={employee.firstName}
            onChange={this.handleChange}
            placeholder="Enter first name"
          />
        </Form.Group>
        <Form.Group controlId="lastName">
          <Form.Label>Last name</Form.Label>
          <Form.Control
            type="text"
            value={employee.lastName}
            onChange={this.handleChange}
            placeholder="Enter last name"
          />
        </Form.Group>
        <Form.Group controlId="birthDate">
          <Form.Label>Date of birth</Form.Label>
          <Form.Control
            type="date"
            value={employee.birthDate}
            onChange={this.handleChange}
          />
        </Form.Group>
        <Form.Group controlId="hireDate">
          <Form.Label>Date of hire</Form.Label>
          <Form.Control
            type="date"
            value={employee.hireDate}
            onChange={this.handleChange}
          />
        </Form.Group>
        <Form.Group controlId="gender">
          <Form.Label>Gender</Form.Label>
          <Form.Control
            as="select"
            value={employee.gender}
            onChange={this.handleChange}
          >
            <option value="">Please select</option>
            <option value="F">Female</option>
            <option value="M">Male</option>
          </Form.Control>
        </Form.Group>
      </div>
    );
  }
}

CreateEmployee.js - Parent ponent

import React from "react";
import { Alert, Form, Col, Row, Button, Card } from "react-bootstrap";
import EmployeeForm from "./EmployeeForm";
import EmployeeService from "./services/EmployeeService";

export default class CreateEmployee extends React.Component {
  constructor() {
    super();
    this.employeeService = new EmployeeService();
    this.state = {
      employee: {
        firstName: "",
        lastName: "",
        birthDate: "",
        hireDate: "",
        gender: ""
      }
    };
  }

  // Create handleChange here and pass it to EmployeeForm as props
  // Use setState instead of mutating state
  handleChange = e => {
    this.setState({employee: {[e.target.id]: e.target.value}})
  };

  save = () => {
    console.log(this.state.values);
    this.employeeService
      .createEmployee(this.state.values)
      .then(result => {
        this.setState({ error: null });
      })
      .catch(err => {
        console.log(err);
        this.setState({ error: err });
      });
  };

  render() {
    console.log("reder : ", this.state.employee);

    return (
      <div>
        <Form>
          <Alert variant="primary">Employee</Alert>

          <Card style={{ width: "500px" }}>
            <Card.Header>Create Employee</Card.Header>
            <Card.Body>
              <EmployeeForm handleChange={this.handleChange} employee={this.state.employee} />
              <Row>
                <Col>
                  <Button variant="primary" type="button" onClick={this.save}>
                    Create
                  </Button>
                </Col>
              </Row>
            </Card.Body>
          </Card>
        </Form>
      </div>
    );
  }
}

Note: I only fixed errors that was required by this question - you might still need to refactor some part of your codes. Don't forget not to mutate the state directly.

Your problem is that you have state in your Parent ponent, and you need to change state in your Parent ponent from a Child ponent. In order to achieve this you need to create handlechange method in your Parent ponent that changes your state and send it with props to your Child ponent.

Here is an example of how you could pass a function from Parent to Child that will use setState to set the state in Parent.

The Parent is a class and the Child is a functional ponent there are no optimizations (you can prevent creating a new reference for the callback function but that would make the example more plicated):

export default class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      employee: {
        firstName: '',
        lastName: '',
        birthDate: '',
        hireDate: '',
        gender: '',
      },
    };
  }
  inputs = ['lastName'];
  render() {
    return (
      <div>
        {this.inputs.map(key => (
          <Child
            key={key}
            //value from this.state
            value={this.state.employee[key]}
            //will set this.state with value passed
            change={val =>
              this.setState({
                ...this.state,
                employee: {
                  ...this.state.employee,
                  [key]: val,
                },
              })
            }
          />
        ))}
      </div>
    );
  }
}

const Child = ({ change, value }) => {
  const onChange e => change(e.target.value);
  return (
    <input type="text" onChange={onChange} value={value} />
  );
};
发布评论

评论列表(0)

  1. 暂无评论