【问题标题】:React-Typescript edit listReact-Typescript 编辑列表
【发布时间】:2022-01-08 12:53:38
【问题描述】:

我正在使用 React-TypeScript 创建员工列表,编辑和删除他们。但是我的编辑按钮在点击时没有做任何事情。关于如何解决此问题的任何想法?

我为“删除”功能使用了相同的代码并且运行良好。以下是我编写了代码的两个 react-typescript 文件,还有一个 app.tsx 文件,所有这些文件都被导入其中。

CreateEmployee.tsx

import React, { useState, FC, ChangeEvent } from "react";
import { Link } from "react-router-dom";
import { IEmployee } from "../../Interfaces";
import EmployeeList from "./EmployeeList";

export const CreateEmployee: FC = () => {
  const [employeeName, setEmployeeName] = useState<string>("");
  const [employeeId, setEmployeeId] = useState<any>("");
  const [employeeList, setEmployeeList] = useState<IEmployee[]>([]);

//   get the data from the input and add it to the state
  const handleChange = (event: ChangeEvent<HTMLInputElement>): void => {
    if (event.target.name === "employeename") {
      setEmployeeName(event.target.value);
    } else {
      setEmployeeId(event.target.value);
    }
  };

// add id and name to the employee list
  const addEmployee = (): void => {
    const newEmployee = {
      employeeId: employeeId,
      employeeName: employeeName,
    };

 setEmployeeList([...employeeList, newEmployee]);
    setEmployeeName("");
    setEmployeeId("");
  };

 // delete employee from the list
  const deleteEmployee = (employeeNameToDelete: string): void => {
    setEmployeeList(
      employeeList.filter(
        (employee) => employee.employeeName !== employeeNameToDelete
      )
    );
  };

// edit employee name and id in the list
  const editEmployee = (
    employeeNameToEdit: string,
    employeeIdToEdit: string
  ): void => {
    setEmployeeList(
      employeeList.map((employee) => {
        if (employee.employeeName === employeeNameToEdit) {
          employee.employeeId = employeeIdToEdit;
        }
        return employee;
      })
    );
  };

 return (


<div>
    <h1>Create Employee</h1>
      <div>
    <label>Employee Id:</label>
    <input
      type="text"
      name="employeeid"
      value={employeeId}
      onChange={(e) => setEmployeeId(e.target.value)}
    />
    <label>Employee Name:</label>
    <input
      type="text"
      name="employeename"
      value={employeeName}
      onChange={(e) => setEmployeeName(e.target.value)}
    />
    <button type="submit" onClick={addEmployee}>
      Submit
    </button>


</div>
  <div>
    <Link to="/employeelist">Employee List</Link>
    <Link to="/engagementList">Engagement List</Link>
  </div>
  <div className="employee-list">
    <h1>Employee List</h1>
    {employeeList.map((employee: IEmployee, key: number) => {
      return (
            <EmployeeList
              key={key}
              employee={employee}
              deleteEmployee={deleteEmployee}
              editEmployee={editEmployee}
            />
          );
        })}
      </div>
    </div>
  );
};

EmployeeList.tsx

import React from "react";
import { IEmployee } from "../../Interfaces";
import { CreateEmployee } from "../employeeComponents/CreateEmployee";
interface Props {
  employee: IEmployee;
  deleteEmployee: (employeeNameToDelete: string) => void;
  editEmployee: (employeeNameToEdit: string, employeeIdToEdit: string) => void;
}
export const EmployeeList = ({ employee, deleteEmployee, editEmployee }: Props) => {
  return (
    <div>
      <div className="employee-list">
        <div className="content">
          <span>{employee.employeeId}</span>
          <span>{employee.employeeName}</span>
        </div>
        <button
          onClick={() => {
            deleteEmployee(employee.employeeName);
          }}
        >
          Delete
        </button>

        <button
          onClick={() => {
            editEmployee(employee.employeeName, employee.employeeId);
          }}
        >
          Edit
        </button>
      </div>
    </div>
  );
};

export default EmployeeList;

【问题讨论】:

    标签: reactjs typescript react-hooks use-state react-typescript


    【解决方案1】:

    问题不在于你改变了状态,你的editEmployee 函数正确地使用了setEmployeeList——map 返回一个新数组,React 检测到这个变化并重新渲染组件。您可以通过将console.log('rendering'); 插入您的CreateEmployee 函数来验证这一点。

    问题在于 editEmployee 只是创建了旧 employeeList 的精确副本。

    您可能希望它使用已编辑的员工 ID 和姓名填充文本字段,然后在单击提交按钮时更新您的员工列表。

    const editEmployee = (
        employeeNameToEdit: string,
        employeeIdToEdit: string
      ): void => {
        // This will put these two items into the text fields for editing
        setEmployeeId(employeeIdToEdit);
        setEmployeeName(employeeNameToEdit);
      };
    

    并将addEmployee 更改为类似的内容(您可以将其重命名为addOrUpdateEmployee):

    const addEmployee = (): void => {
        const newEmployee = {
          employeeId: employeeId,
          employeeName: employeeName,
        };
    
        // Consider it's a new employee if the employee with this employeeId
        // does not exist in the list of employees. 
        // Otherwise, it's an edited employee
        let employeeIndex;
        if (
          employeeList.some((employee, index) => {
            employeeIndex = index;
            return employee.employeeId === employeeId;
          })
        ) {
          // This is not state mutation ...
          employeeList[employeeIndex] = newEmployee;
          // ...because we set it to a copy of the mutated array
          setEmployeeList([...employeeList]);
        } else {
          setEmployeeList([...employeeList, newEmployee]);
        }
    
        setEmployeeName('');
        setEmployeeId('');
      };
    

    决定它是新员工还是编辑员工的逻辑完全是我的,你应该使用适合你的应用程序的任何东西。

    【讨论】:

    • employeeList[employeeIndex] = newEmployee; 实际上是状态突变的定义,employeeList 是当前状态!映射不是状态突变。
    • 是的,从技术上讲是这样,但它没有这样的效果,因为新状态是在之后设置的副本。
    • 肯定有效果。你改变了之前的 state 对象,所以现在 React 不会在employee 元素中看到“更新”的引用差异。 React 戒律之一:你不能改变状态。 React 在这件事上非常简单。
    • 这里的状态是整个数组(或者更确切地说是它的引用),新数组提供给setEmployeeList,因为它是一个不同数组引用,React 会重新渲染。如果你运行代码,你可以看到它工作。
    • 你不懂。该数组显然是一个新数组,数组通过引用复制,但这不是突变,也不是问题。问题是数组中元素 in 的突变。 state 是整个数组,是的,state 也是数组的每个元素,每个元素的每个属性,等等……是的,有一个新数组,是的,这会触发 React重新渲染数组,并且这样做会检查映射到 JSX 的每个元素的引用,如果元素引用没有改变,它可以重新渲染,因此你不会在 UI 中看到变化。
    【解决方案2】:

    您在其设置器中使用当前状态的值employeeList。而不是将对象传递给useStateyou can pass a function instead that takes the old state as a parameter。例如:

    setEmployeeList((oldEmployeeList) => 
          (oldEmployeeList.map((employee) => {
            if (employee.employeeName === employeeNameToEdit) {
              employee.employeeId = employeeIdToEdit;
            }
            return employee;
          }))
        );
    

    【讨论】:

    • 我只有一个employeeList,oldEmployeeList是什么意思?
    • 状态的前一个值(employeeList的旧值)
    • 我需要定义一个新的状态吗?
    • @Sevicode 它只是在功能状态更新期间传递的前一个状态参数的名称。
    • 不,它仍然无法正常工作,我什至没有收到错误。
    【解决方案3】:

    这是一个状态突变的问题,您正在改变您正在编辑的员工对象,而不是返回 new 员工对象引用。由于特定的 employee 对象引用没有改变,React 可能会放弃重新渲染它们,因为它在协调期间使用浅层引用相等检查。

    const editEmployee = (
      employeeNameToEdit: string,
      employeeIdToEdit: string
    ): void => {
      setEmployeeList(employeeList => employeeList.map((employee) => {
        if (employee.employeeName === employeeNameToEdit) {
          return {                        // <-- return new object reference
            ...employee,                  // <-- shallow copy previous state
            employeeId: employeeIdToEdit, // <-- set property value
          }
        }
        return employee; // <-- else return previous state
      }));
    };
    

    【讨论】:

    • 嘿,Drew,一个新手来了:D 你说的浅拷贝以前的状态是什么意思?
    • @Sevicode 表示将所有属性引用复制到一个新的数组/对象中。当您{ ...employee } 时,您复制了属性,但它们是通过引用复制的,换句话说,它们仍然是引用您从中复制的旧对象。浅拷贝之后,您将创建新的引用,即设置一个新的 employeeId 属性。 React 通过使用浅引用相等检查来工作,如果引用仍然指向与先前渲染相同的东西,则假定它没有改变。这就是为什么状态突变在 React 中很重要并且非常反模式的原因。
    • @Sevicode 这里有答案解决/解决了您的问题/问题?不要忘记someone answers时要做什么。
    猜你喜欢
    • 2018-12-25
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 2019-02-02
    • 1970-01-01
    相关资源
    最近更新 更多