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.
>Solution :
function App() {
// ...
function ComponentList(){
// ...
}
}
You’ve defined ComponentList inside of App. This isn’t supported. Every time App rerenders, you create a brand new definition for ComponentList. 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 variable
function App() {
const [list, setList] = useState(["1", "2", "3", "4"]);
// ...
<ComponentList list={list}/>
// ...
}
function ComponentList({ list }){
return(<>
{list.map(i => <Number num={i} key={i}/>) }
</>)
}