首页 > 解决方案 > 如何将 onchange 事件绑定到特定行的元素?

问题描述

我正在获取所有用户的数据,并在表格中显示该数据。我能够获取特定行的用户 ID,现在我正在尝试为该特定行的元素添加 onchange 事件。当我单击编辑按钮时,所有输入字段都在取值,但所有值都在该类别下发生变化。例如,如果我单击编辑并开始输入名称,则名称列中的所有字段都在更改。我只想更改相应行上的特定字段

import React, { Component } from "react";
import { getAllDash, updateAdminUser } from "../fetchingData/api_calls";
import "./profile.css";
import { Table } from "reactstrap";

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

    this.state = {
      users: [],
      edit: false,
      firstname: "",
      lastname: "",
      phone: "",
      email: "",
      error: false,
      verification: false,
      role: "user",
      input: "",
    };
  }

  componentDidMount() {
    const token = localStorage.getItem("jwt");
    getAllDash(token).then((data) => {
      data.map((user_id, idx) => {
        this.setState({
          users: data,
        });
      });
    });
  }
  editbtn = (id) => {
    console.log("id is..", id);
    this.setState((state) => ({
      // edit: !this.state.edit,
      users: state.users.map((csid) => {
        if (csid.user_id === id.user_id) {
          console.log(id.user_id);
          return {
            ...csid,
            edit: !state.edit,
            log: console.log("state is if", !state.edit),
            // edit: this.state.edit,
          };
        } else {
          console.log("state is else", this.state.edit);
          return csid;
        }
      }),
      edit: !this.state.edit,
      // log: console.log("state is edit", !this.state.edit),
      // edit:state.edit
    }));
    this.editbtn = this.editbtn.bind(this);
  };
  renderTableData() {
    return this.state.users.map((data, index) => {
      const {
        user_id,
        user_firstname,
        user_lastname,
        user_phone,
        user_email,
        user_role,
        user_verification,
      } = data; //destructuring

      return (
        <tr key={user_id}>
          <td> {++index}</td>
          <td> {user_id}</td>
          <td>
            {" "}
            <input
              value={this.state.firstname}
              onChange={(e) => {
                this.setState({ firstname: e.target.value })}}
              placeholder={user_firstname}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            {" "}
            <input
              value={this.state.lastname}
              onChange={(e) => this.setState({ lastname: e.target.value })}
              placeholder={user_lastname}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            {" "}
            <input
              value={this.state.email}
              onChange={(e) => this.setState({ email: e.target.value })}
              placeholder={user_email}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            {" "}
            <input
            value={this.state.role}
            // onChange={(e) => this.setState({ firstname: e.target.value })}
              placeholder={user_role}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            {" "}
            <input
              value={this.state.phone}
              onChange={(e) => this.setState({ phone: e.target.value })}
              placeholder={user_phone}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            {" "}
            <input
              value={this.state.verification}
              placeholder={user_verification}
              disabled={!this.state.edit}
            />
          </td>
          <td>
            <button onClick={(e) => this.editbtn(data, e)} key={data.user_id}>
              {this.state.edit ? "Cancel" : "edit"}
            </button>
            <button>Save changes</button>
          </td>
        </tr>
      );
    });
  }

  render() {
    return (
      <div className="adminDash">
        <Table>
          <thead>
            <tr>
              <th id="number">No.</th>
              <th>User Id</th>
              <th>User First Name</th>
              <th>User Last Name</th>
              <th>User Email</th>
              <th>User Role</th>
              <th>User Phone</th>
              <th>user verification</th>
              <th>User status</th>
            </tr>
          </thead>
          <tbody>{this.renderTableData()}</tbody>
        </Table>
      </div>
    );
  }
}

export default AdminDash;

标签: javascriptreactjsapi

解决方案


问题

除了edit每行中的每个输入都使用单一状态之外,当您处于编辑模式时,每个输入都使用相同的状态来提供它们的value属性。

主要问题是映射的行数据并没有真正被使用。

解决方案

  1. 更新editbtn回调以简单地切换编辑模式。不过,不要切换布尔值,而是在null和用户之间切换,user_id这样您就可以匹配要编辑的行。

    editbtn = (data) => {
      const {
        user_id
      } = data;
    
      this.setState((prevState) => ({
        edit: prevState.edit === user_id ? null : user_id
      }));
    };
    
  2. 实施componentDidUpdate以根据当前edit状态值填充或重置字段状态值。如果edit为真,则在数组中搜索用户,users如果找到,则填充状态,否则重置字段状态值。

    componentDidUpdate(prevProps, prevState) {
      if (prevState.edit !== this.state.edit) {
        if (this.state.edit) {
          const user = this.state.users.find(
            (user) => user.user_id === this.state.edit
          );
    
          if (user) {
            this.setState({
              firstname: user.user_firstname,
              lastname: user.user_lastname,
              phone: user.user_phone,
              email: user.user_email,
              verification: user.user_verification,
              role: user.user_role
            });
          }
        } else {
          this.setState((prevState) => ({
            firstname: "",
            lastname: "",
            phone: "",
            email: "",
            verification: false,
            role: "user"
          }));
        }
      }
    }
    
  3. 计算一个isEditable值以传递给disabled输入的属性。

  4. 此外,如果特定用户/行是可编辑的,则有条件地传递用户数据值或存储编辑值的字段状态

    renderTableData() {
      return this.state.users.map((data, index) => {
        const {
          user_id,
          user_firstname,
          ...
        } = data; //destructuring
    
        const isEditable = this.state.edit === user_id;
    
        return (
          <tr key={user_id}>
            <td> {index + 1}</td>
            <td> {user_id}</td>
            <td>
              <input
                value={isEditable ? this.state.firstname : user_firstname}
                onChange={(e) => {
                  this.setState({ firstname: e.target.value });
                }}
                placeholder={user_firstname}
                disabled={!isEditable}
              />
            </td>
            ...
    
  5. 为了完成,实现“保存数据”按钮的回调。这将获取字段状态数据并更新users状态数组中的用户记录。这也清除了字段输入状态值并重置edit返回以null使该行退出编辑模式。

    saveData = () => {
      this.setState((prevState) => ({
        users: prevState.users.map((user) =>
          user.user_id === prevState.edit
            ? {
                ...user,
                user_firstname: prevState.firstname,
                user_lastname: prevState.lastname,
                user_phone: prevState.phone,
                user_email: prevState.email,
                user_role: prevState.role,
                user_verification: prevState.verification
              }
            : user
        ),
        edit: null,
        firstname: "",
        lastname: "",
        phone: "",
        email: "",
        verification: false,
        role: "user"
      }));
    };
    
  6. 中的小问题componentDidMount。你遍历你的data数组并将一堆状态更新排入队列,这些状态更新只是将相同的更新排入队列。这里不需要一个data.map,一个this.setState({ users: data });就足够了。

    componentDidMount() {
      const token = localStorage.getItem("jwt");
      getAllDash(token).then((data) => {
        this.setState({ users: data });
      });
    }
    

演示

编辑 how-to-bind-onchange-event-to-a-particular-rows-element

完整的沙盒代码:

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

    this.state = {
      users: [],
      edit: null,
      firstname: "",
      lastname: "",
      phone: "",
      email: "",
      error: false,
      verification: false,
      role: "user",
      input: ""
    };
  }

  componentDidMount() {
    this.setState({ users: data });
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.edit !== this.state.edit) {
      if (this.state.edit) {
        const user = this.state.users.find(
          (user) => user.user_id === this.state.edit
        );

        if (user) {
          this.setState({
            firstname: user.user_firstname,
            lastname: user.user_lastname,
            phone: user.user_phone,
            email: user.user_email,
            verification: user.user_verification,
            role: user.user_role
          });
        }
      } else {
        this.setState((prevState) => ({
          firstname: "",
          lastname: "",
          phone: "",
          email: "",
          verification: false,
          role: "user"
        }));
      }
    }
  }

  editbtn = (data) => {
    console.log("data is..", data);

    const { user_id } = data;

    this.setState((prevState) => ({
      edit: prevState.edit === user_id ? null : user_id
    }));
  };

  saveData = () => {
    this.setState((prevState) => ({
      users: prevState.users.map((user) =>
        user.user_id === prevState.edit
          ? {
              ...user,
              user_firstname: prevState.firstname,
              user_lastname: prevState.lastname,
              user_phone: prevState.phone,
              user_email: prevState.email,
              user_role: prevState.role,
              user_verification: prevState.verification
            }
          : user
      ),
      edit: null,
      firstname: "",
      lastname: "",
      phone: "",
      email: "",
      verification: false,
      role: "user"
    }));
  };

  renderTableData() {
    return this.state.users.map((data, index) => {
      const {
        user_id,
        user_firstname,
        user_lastname,
        user_phone,
        user_email,
        user_role,
        user_verification
      } = data; //destructuring

      const isEditable = this.state.edit === user_id;

      return (
        <tr key={user_id}>
          <td> {index + 1}</td>
          <td> {user_id}</td>
          <td>
            <input
              value={isEditable ? this.state.firstname : user_firstname}
              onChange={(e) => {
                this.setState({ firstname: e.target.value });
              }}
              placeholder={user_firstname}
              disabled={!isEditable}
            />
          </td>
          <td>
            <input
              value={isEditable ? this.state.lastname : user_lastname}
              onChange={(e) => this.setState({ lastname: e.target.value })}
              placeholder={user_lastname}
              disabled={!isEditable}
            />
          </td>
          <td>
            <input
              value={isEditable ? this.state.email : user_email}
              onChange={(e) => this.setState({ email: e.target.value })}
              placeholder={user_email}
              disabled={!isEditable}
            />
          </td>
          <td>
            <input
              value={isEditable ? this.state.role : user_role}
              // onChange={(e) => this.setState({ firstname: e.target.value })}
              placeholder={user_role}
              disabled={!isEditable}
            />
          </td>
          <td>
            <input
              value={isEditable ? this.state.phone : user_phone}
              onChange={(e) => this.setState({ phone: e.target.value })}
              placeholder={user_phone}
              disabled={!isEditable}
            />
          </td>
          <td>
            <input
              value={isEditable ? this.state.verification : user_verification}
              placeholder={user_verification}
              disabled={!isEditable}
            />
          </td>
          <td>
            <button onClick={() => this.editbtn(data)}>
              {isEditable ? "Cancel" : "edit"}
            </button>
            <button onClick={this.saveData}>Save changes</button>
          </td>
        </tr>
      );
    });
  }

  render() {
    return (
      <div className="adminDash">
        <Table>
          <thead>
            <tr>
              <th id="number">No.</th>
              <th>User Id</th>
              <th>User First Name</th>
              <th>User Last Name</th>
              <th>User Email</th>
              <th>User Role</th>
              <th>User Phone</th>
              <th>user verification</th>
              <th>User status</th>
            </tr>
          </thead>
          <tbody>{this.renderTableData()}</tbody>
        </Table>
      </div>
    );
  }
}

推荐阅读