I'm looking at the TransitionGroup documentation example, and I'm trying to update it to run the CSSTransition whenever the text
value is updated for an existing item.
I have set up a codesandbox to show my current attempt.
const [items, setItems] = useState([
{ id: 1, text: 'Hello world!' },
{ id: 2, text: 'How are you?' },
]);
return (
<Container style={{ marginTop: '2rem' }}>
<ListGroup style={{ marginBottom: '1rem' }}>
<TransitionGroup className="todo-list">
{items.map(({ id, text }) => (
<CSSTransition
key={id}
timeout={500}
classNames="item">
<ListGroup.Item>{text}</ListGroup.Item>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
<Button
onClick={() => {
setItems((items) => [
{ id: 1, text: 'Hello to you!' },
{ id: 2, text: 'How do you do?' },
]);
}}>
Update Items
</Button>
</Container>
);
When I click the button, the text content updates without the CSSTransition. I know this is because of the id
not changing, and this is what key
is set to, but how do I have TransitionGroup take into account the text
value?
How do I keep the same id
but update the text value with a transition?
Since key={id}, the key won't change when the text is updated, and the CSSTransition won't trigger because it doesn't get rerendered.
We can change the key
to include the id
and the text
, so the component will always get rerendered when the text changes. We also want to add exit={false}
to prevent us from seeing extra components while the new components are transitioning in. Here's what that should look like:
<CSSTransition
key={`${id}${text}`}
timeout={500}
classNames="item"
exit={false}
>
Here's a codesandbox example of this solution.