Darkbound
Darkbound

Reputation: 3434

Updating state of parent component sets child state to default values

I have a table with collapsible rows, and I have two components for them, the parent is the Table the child is each CollapsibleRow.

The table tracks the state of items in useEffect, and updates whenever something changes.

Each row also has its own state to track if its collapsed or not, default is collapsed (in my case false).

Whenever the state of the Table changes, the collapsed state, gets set back to false (i.e. if a row was "opened" when the state change occurs, it gets closed, because its state gets set back to default closed state).

export default function Table() {
  const { stock } = useContext(stockContext);

  return (<Table>
            {stock.map(stockItem => <TableCollapsibleRow key={uuidv4()} stockItem={stockItem}/>)}
         </Table>)
}

And the basics of the row:

export default function TableCollapsibleRow({ stockItem }) {
  const [stockItemOpen, setStockItemOpen] = useState(false);

  const openCloseOnClickHandler = () => {
    setStockItemOpen(prevState => !prevState);
  }

  return <Collapse onClick={openCloseOnClickHandler} in={stockItemOpen}><TableRow>.....</TableRow></Collapse>
}

So if stockItemOpen is true (the row is not collapsed and the additional stuff can be viewed), and stock changes while it is true, its set back to the default false and it gets collapsed.

I have tried to make an arbitrary stuff variable, to see if it the behavior is somehow related to the implementation of the table:

  const [stuff, setStuff] = useState(false);

  const openCloseOnClickHandler = () => {
    setStuff(true);
    setStockItemOpen((prevState) => !prevState);
  };

  console.log(`${stuff} stuff`);

It too gets set back to false, whenever state gets updated.

As far as the context of stock goes:

  const [stock, setStock] = useState([]);

  const addToStockOperation = (data) => {
    ..do some stuff with the data..

    setStock(prevStock => ...code that sets new stock...)
  }

And this addToStockOperation method is used by a button within the TableCollapsibleRow component.

Upvotes: 0

Views: 267

Answers (1)

dbuchet
dbuchet

Reputation: 1651

You need to have a unique key in your map

{
 stock.map(stockItem => <TableCollapsibleRow key={stockItem.id} stockItem={stockItem}/>)
}

This way, React can keep tracks of children, and keep their inner states

-- UPDATE --

I see you've udapted for uuidv4 in key. So at each render, you're generating a new key. So for React, it's a new component! You have to keep same ids at each render (that's why I was suggesting stockItem.id)

Upvotes: 3

Related Questions