0

I'm new to react and the hooks api and I'm struggling with figuring how react keeps track of the state.

I tried to build a table component which takes a column config and rows as input. The columns have callback functions that is called when for example the column header is clicked so that the parent can for example sort the rows. However when the callback is called the rows are always set to the default value. Why is this happening? Is it because how closuer works in javascript? Is there any way to access the "latest" state of items inside my callback function?

Here is a simplified version of my component, https://codepen.io/Abrissirba/pen/OJyPvXx. Start with adding a couple of rows, then click Column 1 to sort the table. items will now be set to the initial value and the added rows will therefore dissapear.

function DetailsListHookComponent({items, columns}) { 
  return (
    <table>
      <thead>
        <tr>
          {columns.map(x => (<td key={x.key} onClick={() => x.onClick(x)}>{x.title}</td>))}
        </tr>
      </thead>
      <tbody>
      {items.map(x => {
       return (
        <tr key={x.id}>
          {columns.map(y => <td key={y.key}>{x[y.key]}</td>)}
        </tr>)
      })}
    </tbody>
    </table>
  )
}

let newId = 3;
function ContainerComponent() {
  const [items, setItems] = React.useState([
    {id: 1, 1: 1, 2:2}, 
    {id: 2, 1:10, 2:20}
  ]);

  const [columns, setColumns] = React.useState([{
    key: 1,
    title: 'Column 1',
    sortOrder: '1',
    onClick: (column) => {
      const dir = column.sortOrder * -1;
      setItems([...items.sort((a, b) => {
        const order = a['1'] > b['1'] ? 1 : a['1'] < b['1'] ? -1 : 0;
        return order * dir;
      })]);

      setColumns([{
        ...column, 
        sortOrder: dir
      }]);
    }
  }]);

  return (
    <>
      <DetailsListHookComponent items={items} columns={columns}></DetailsListHookComponent>
      <button onClick={() => setItems([...items, {id: newId++, 1: newId*10, 2: newId*20}])}>Add</button>
    </>
  )
}
Abris
  • 1,451
  • 3
  • 18
  • 38
  • Yes, this is how closures work. Callback should be defined outside hook and passed to component. – Drew Reese Apr 11 '20 at 08:32
  • similar problem to https://stackoverflow.com/q/54069253/1176601 - with a fix of the immediate problem by using [functional updates](https://reactjs.org/docs/hooks-reference.html#functional-updates) `setItems(currentItems => [...currentItems.sort()])` – Aprillion Apr 11 '20 at 09:15

0 Answers0