I have two components in my react (ts) app.
App.tsx:
import { useState } from 'react'
import Number from './Number'
import './App.css'
function App() {
const [list, setList] = useState(["1", "2", "3", "4"]);
const [x, setX] = useState({});
function ComponentList(){
return(<>
{list.map(i => <Number num={i} key={i}/>) }
</>)
}
return (
<div className="App">
<ComponentList/>
<div onClick={()=>{
setX({});
}}>Update</div>
</div>
)
}
export default App
Number.tsx:
import React, {useState} from 'react'
type props = {
num: string
}
function Number({num}:props) {
const [color, setColor] = useState("rgb(0, 0, 0)");
return (
<div style={{color: color}} onClick={()=>{
setColor("rgb(255, 255, 255)");
}}>
{num}
</div>
)
}
export default Number
Here’s the problem:
When any state on the parent component (App.tsx) changes, the Number components in the list re-mount, resetting all their states to initial value. How can I get rid of this problem while keeping the list component?
The issue is very simple to re-create. When you use these two components in a react app and click the numbers to change their color, the color is reset upon clicking the "update" button, which seems illogical to me since the "setX" call doesn’t change anything about the list.
2
Answers
You’ve defined
ComponentList
inside ofApp
. This isn’t supported. Every timeApp
rerenders, you create a brand new definition forComponentList
. Its code may have the same text as the previous one, but it’s a different function, so a different component type as far as react is concerned. So react has to unmount the old ones and mount the new ones.The fix is to move the component out. You’ll need to change
list
to be a prop instead of a closure variableYou created your
ComponentList
inside the parent, and since you don’t useuseCallback
, it is recreated when the parent re-render.Here is how to implement both solutions, but the best one is to take your component outside of the parent :
Here is the repro on Stackblitz
Also, here is a video of Jeff Herrington about this exact problem.