【问题标题】:react child/parent component - onChange event just takes one character and not retaining value反应子/父组件 - onChange 事件只需要一个字符而不保留值
【发布时间】:2020-01-16 03:59:38
【问题描述】:

在 ReactJS 中,在我的子组件中,输入 > 文本上的 onChange() 事件仅采用一个值,而不是在每次按键时保留以前的值。

我正在尝试捕获子表单中的输入并希望将其传输给父表单。实际上,我正在尝试将子表单重用于创建和编辑页面。

我的完整代码框在这里 https://codesandbox.io/embed/sleepy-stallman-fbyhh?fontsize=14

子组件

    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>
        );
      }
    }

父组件

    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>
        );
      }
    }

【问题讨论】:

  • 您正在改变状态:this.props.employee[e.target.id] = e.target.value; 将更改函数从父级传递给子级,该函数执行 setState 而不会发生变异。
  • 谢谢,这是真正的孩子与父母的沟通。一旦用户在子表单中输入所有数据,我想将其传输给父表单。

标签: javascript reactjs


【解决方案1】:

所以我浏览了代码沙箱上的代码并进行了以下更改 - 明显的更改将 cmets 放在了顶部: 你可以在这里查看它们 - https://codesandbox.io/s/react-parent-child-1fif1?fontsize=14

你不应该做以下事情:

  • 直接改变状态

  • 尝试从子组件的 props 中改变父组件中的状态

EmployeeForm.js - 子组件

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 - 父组件

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>
    );
  }
}

注意:我只修复了此问题所需的错误 - 您可能仍需要重构部分代码。不要忘记不要直接改变状态。

【讨论】:

  • 谢谢,handleChange() 帮助解决了这个问题。
【解决方案2】:

这是一个示例,说明如何将一个函数从 Parent 传递给 Child,该函数将使用 setState 在 Parent 中设置状态。

Parent 是一个类,Child 是一个功能组件,没有优化(您可以阻止为回调函数创建新引用,但这会使示例更加复杂):

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} />
  );
};

【讨论】:

    【解决方案3】:

    您的问题是您的Parent 组件中有状态,您需要从Child 组件更改您的Parent 组件中的状态。为了实现这一点,您需要在 Parent 组件中创建 handlechange 方法来更改您的状态并将其与道具一起发送到您的 Child 组件。

    【讨论】:

      猜你喜欢
      • 2017-01-23
      • 2019-12-04
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      • 1970-01-01
      相关资源
      最近更新 更多