score:1

Accepted answer

you need some way of being able to identify the row being edited, and a place to save the current edited data. that can be achieved by using state.

when the id of an object in your data array matches the current selected row (after you've clicked the edit button) return one set of row data that includes input elements. if the id doesn't match, return normal row data.

here's a minimal working example.

const { usestate } = react;

const data = [
  { id: 1, name: 'rita', age: 22 },
  { id: 2, name: 'sue', age: 42 },
  { id: 3, name: 'bob', age: 12 }
]

function example({ data }) {

  // have states for the data, the current selected row
  // and the data that is currently being edited
  const [ rowdata, setrowdata ] = usestate(data);
  const [ selectedrow, setselectedrow ] = usestate(0);
  const [ editdata, seteditdata ] = usestate({});

  // compiles the row data
  function getrows() {
    
    return rowdata.map((obj, i) => {

      // get the id, name, and age from the
      // current object
      const { id, name, age } = obj;
      
      // if the id of the current object equals
      // the selected row return a set of row data with input
      // elements (not id though) auto-populated with the
      // information from that object
      if (id === selectedrow) {
        return (
          <tr>
            <td>{editdata.id}</td>
            <td>
              <input
                classname="edit"
                type="text"
                name="name"
                value={editdata.name}/>
            </td>
            <td>
              <input
                classname="edit"
                type="text"
                name="age"
                value={editdata.age}
              />
            </td>
            <button
              data-id={id}
              data-action="save"
            >save
            </button>
          </tr>
        );
      }
      
      // otherwise return a set of non-editable
      // row data
      return (
        <tr>
          <td>{id}</td>
          <td>{name}</td>
          <td>{age}</td>
          <button
            data-id={id}
            data-action="edit"
          >edit
          </button>
        </tr>
      );
    
    });

  }

  // when a button has been clicked
  // note: because we're using event delegation
  // (attaching listeners to the table element instead
  // of all the rows) we need to check that element
  // we clicked on is the button
  function handleclick(e) {
    
    const { nodename } = e.target;
    
    if (nodename === 'button') {
      
      const { id, action } = e.target.dataset;
      
      // if the button action is edit, set the
      // selected row state, and auto-populate the
      // editdata state
      if (action === 'edit') {
        setselectedrow(+id);
        const obj = data.find(obj => obj.id === +id);
        seteditdata({...obj});
      }
      
      // if the action is save filter out the matching
      // object from the data state, and then update the data
      // with the filtered object, plus the object in
      // the editdata state, making sure you sort by id
      // otherwise the edited row will appear at the bottom
      // then reset the states
      if (action === 'save') {
        const filtered = data.filter(obj => obj.id !== selectedrow);
        const updated = [...filtered, editdata];
        updated.sort((a, b) => a.id - b.id);
        setrowdata(updated);
        setselectedrow(0);
        seteditdata({});
      }

    }
  
  }

  // when an input changes
  // again we need to check that the element
  // that has changed is an input
  function handlechange(e) {
    
    const { nodename } = e.target;
    
    // update the editdata state using the input
    // name and value
    if (nodename === 'input') {
      const { name, value } = e.target;
      seteditdata({ ...editdata, [name]: value });
    }
  
  }

  // we attach two listeners to the table element
  // one to catch clicks from the button
  // the other to catch changes to the inputs if
  // we're in edit mode
  return (
    <table
      onclick={handleclick}
      onchange={handlechange}
    >
      <tr class="heading">
        <td>id</td>
        <td>name</td>
        <td>age</td>
      </tr>
      <tbody>
        {getrows()}
      </tbody>
    </table>
  );
};

reactdom.render(
  <example data={data} />,
  document.getelementbyid('react')
);
table { border: 1px solid #898989; border-collapse: collapse; }
td, input { width: 75px; text-align: center; }
td { padding: 0.2em; border: 1px solid #898989; }
.heading { background-color: #efefef; text-align: center; font-weight: 600; }
.edit { background-color: #ffffcc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>


Related Query

More Query from same tag