简体   繁体   中英

onChange in react not working as I would expect

given this datatype for tables an array of object of objects:

[
    {
        "1": {
            "1": "Item s ",
            "2": "Manufacturer ",
            "3": "Mir s ",
            "4": "Decoription ",
            "5": "Contents ",
            "6": "UOM ",
            "7": "Total Ship Total Qty ",
            "8": "% of Purohasec ",
            "9": "Involoe Count ",
            "10": "K Brand "
        },
        "2": {
            "1": "fdsa ",
            "2": "fdsa fdsa ",
            "3": "16-fsd ",
            "4": "fds fdsa TW fsda",
            "5": "100 ",
            "6": "B) ",
            "7": "6 ",
            "8": "0.17 ",
            "9": "3 ",
            "10": ""
        },
      }, 
    ....
]

I have this component that displays a "row" to be edited. I am displaying the form and table backed by the json data (above), thinking I work with the table and set it in state, the the view re-renders and gives me the change. The datatype above will be in the above format, but the headers, number of tables, fields could all change from run to run. Also I don't have much control over the data type. The table being passed as a prop is tablesCopy you see below in the cellChange.

const [tablesCopy, setTablesCopy] = useState<any>({});

...

const InvRow = ({ rowTarget, clearEditRow, table, cellChange }: { rowTarget: string, clearEditRow: Function, table: any; cellChange: Function; }) => {
  const tt = tableTarget(rowTarget);

  const editRow = [];

  if (tt) {
    const labels = table[tt.table][1];
    const values = table[tt.table][tt.row];

    const keys = Object.keys(labels);
    for (let key of keys) {
      const name = `t_${tt.table}_r_${tt.row}_c_${key}`;
      editRow.push(<tr>
        <td>{labels[key]}</td>
        <td><Input type="text" value={values[key]} name={name} id={name} onChange={(e) => cellChange(e)} /></td>
      </tr>);
    }
  }

  return (
    <>
      <Table>{editRow}</Table>
      <div>
        <Button onClick={(e) => clearEditRow(e)} color="primary" size="lg">Close</Button>
      </div>
    </>

  );
};

my on cellChange method is the following, and it is fired correctly with expected inputs:

  const cellChange = (e: React.BaseSyntheticEvent) => {

    const tt = tableTarget(e.target.id);
    console.log("cellChange -> tt", tt);
    tablesCopy[tt.table][tt.row][tt.cell] = e.target.value;
    setTablesCopy(tablesCopy);

  };

however, in the display, the old values are not getting replaced by the onChange event, though in the console, i can see the event getting fired with the correct values.

Any suggestion to implement this onChange better, or a differnt tact i should be taking?

edit: adding my useEffect initialization:

  useEffect(() => {
    const fetchData = async () => {
      const path = "/tables.json";
      const response = await fetch(path);
      const tables: any = await response.json();
      setTablesOrig(tables);
      setTablesCopy({ ...tables });
      const tableKeys = Object.keys(tablesCopy);
      setNumOfTables(tableKeys.length);

    };
    fetchData();
  }, []);

You should clone your data object. If you're using just string , number and bool in your table, this should work just fine:

const cellChange = (e: React.BaseSyntheticEvent) => {

    const tt = tableTarget(e.target.id);
    console.log("cellChange -> tt", tt);
    var tables = JSON.parse(JSON.stringify(tablesCopy)); // <- clone
    tables[tt.table][tt.row][tt.cell] = e.target.value;
    setTablesCopy(tables);

  };

see other options of deep object clone here: What is the most efficient way to deep clone an object in JavaScript?

UPD: As mentioned in comments you could use spread syntax to copy, however, it's not enought to do {...tablesCopy} but you should also clone that table, row and cell you're changing. So right way would be as follows:

const cellChange = (e: React.BaseSyntheticEvent) => {

    const tt = tableTarget(e.target.id);
    console.log("cellChange -> tt", tt);

    var tables = {
        ...tablesCopy,
        [tt.table]: {
            ...tablesCopy[tt.table],
            [tt.row]: {
                ...tablesCopy[tt.table][tt.row],
                [tt.cell]: e.target.value
            }
        }
    };
    setTablesCopy(tables);

  };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM