反应useState钩子不显示数组的正确状态

时间:2019-12-22 17:46:47

标签: reactjs react-hooks

我有两个功能组件,而我从父组件中动态创建了一组控件。基于创建的每个项目,我想删除它们,但是每次删除最后一个。例如,当我删除第二个或第一个时创建的三行,最后一个被删除。

Education.jsx

function Education(props) {
  const blankEdu = { id: 0, name: "", percentage: "", year: "" };
  const [eduState, setEduState] = useState([{ ...blankEdu }]);

  const addEducation = () => {
    setEduState([...eduState, { ...blankEdu }]);
  };

  function handleRemove(index) {
    console.log(index);
    if (eduState.length != 1) {
      const updatedEdu = [...eduState];
      updatedEdu.splice(index, 1);
      setEduState([...updatedEdu]);
    }
  }

  const handleEducationChange = (index, e, c) => {
    const updatedEdu = [...eduState];
    updatedEdu[index][c] = e.target.value;
    updatedEdu[index]["id"] = index;
    setEduState(updatedEdu);
  };
  return (
    <div>
      <div className="shadow p-3 mb-5 bg-white rounded">
        Final Step: Education
      </div>
      {eduState.map((val, idx) => (
        <div
          key={idx}
        >
          <EducationInput
            key={`edu-${idx}`}
            idx={idx}
            handleEducationChange={handleEducationChange}
          />
          {eduState.length > 1 ? (
            <Button variant="danger" onClick={() => handleRemove(idx)}>
              Remove Course
            </Button>
          ) : null}
        </div>
      ))}
      <Button variant="outline-info" onClick={addEducation}>
        Add New Degree
      </Button>
    </div>
  );
}

export default Education;

EducationInput.jsx

const EducationInput = ({ idx, handleEducationChange }) => {
  return (
    <div key={`edu-${idx}`} id={`edu-${idx}`}>
      <span className="border border-success">
        <Form>
          <Form.Group as={Row}>
            <Form.Label column sm={3}>
              {`Course #${idx + 1}`}:
            </Form.Label>
            <Col sm={5}>
              <input
                type="text"
                onChange={e => handleEducationChange(idx, e, "name")}
              />
            </Col>
          </Form.Group>
          <Form.Group as={Row}>
            <Form.Label column sm={3}>
              Passing Year:
            </Form.Label>
            <Col sm={5}>
              <input
                type="text"
                onChange={e => handleEducationChange(idx, e, "year")}
              />
            </Col>
          </Form.Group>
        </Form>
      </span>
    </div>
  );
};

export default EducationInput;

我通过在控制台上打印来检查并验证了updateEdu的值。它在控制台上提供了正确的输出,但是setEduState函数在UI上无法正确更新,不知道为什么。

1 个答案:

答案 0 :(得分:1)

您依赖项目的索引,但是在添加或删除元素时索引会发生变化,因此它们不可靠。

创建新教学时,您需要生成一个自动的唯一ID。 例如,uuid软件包在此任务中很受欢迎。

我对您的代码进行了一些重构以使其正常工作:

教育:

import React, { useState } from "react";
import EducationInput from "./EducationInput";
import Button from "react-bootstrap/Button";
import uuidv4 from "uuid/v4";

function Education(props) {
  const blankEdu = { id: "", name: "", percentage: "", year: "" };
  const [eduState, setEduState] = useState([{ ...blankEdu }]);

  const addEducation = () => {
    setEduState([...eduState, { ...blankEdu, id: uuidv4() }]);
  };

  function handleRemove(id) {
    console.log(id);
    if (eduState.length > 1) {
      const updatedEdus = eduState.filter(edu => edu.id !== id);
      setEduState(updatedEdus);
    }
  }

  const handleEducationChange = (id, field, value) => {
    console.log(field, value);
    let updatedEducations = eduState.map(edu => {
      if (edu.id === id) return edu;

      edu[field] = value;
      return edu;
    });

    setEduState(updatedEducations);
  };
  return (
    <div>
      <div className="shadow p-3 mb-5 bg-white rounded">
        Final Step: Education
      </div>
      {eduState.map(val => (
        <div key={val.id}>
          <EducationInput
            key={`edu-${val.id}`}
            idx={val.id}
            handleEducationChange={handleEducationChange}
          />
          {eduState.length > 1 ? (
            <Button variant="danger" onClick={() => handleRemove(val.id)}>
              Remove Course
            </Button>
          ) : null}
        </div>
      ))}
      <Button variant="outline-info" onClick={addEducation}>
        Add New Degree
      </Button>
      <br />
      <br />
      Educations in json:{JSON.stringify(eduState)}
    </div>
  );
}

export default Education;

EducationInput

import React from "react";
import Form from "react-bootstrap/Form";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";

const EducationInput = ({ idx, handleEducationChange }) => {
  return (
    <div key={`edu-${idx}`} id={`edu-${idx}`}>
      <span className="border border-success">
        <Form>
          <Form.Group as={Row}>
            <Form.Label column sm={3}>
              {`Course #${idx + 1}`}:
            </Form.Label>
            <Col sm={5}>
              <input
                type="text"
                name="name"
                onChange={e =>
                  handleEducationChange(idx, e.target.name, e.target.value)
                }
              />
            </Col>
          </Form.Group>
          <Form.Group as={Row}>
            <Form.Label column sm={3}>
              Passing Year:
            </Form.Label>
            <Col sm={5}>
              <input
                type="text"
                name="year"
                onChange={e =>
                  handleEducationChange(idx, e.target.name, e.target.value)
                }
              />
            </Col>
          </Form.Group>
        </Form>
      </span>
    </div>
  );
};

export default EducationInput;

Codesandbox