英文:
Parent state getting reset back to initial value after different child is clicked
问题
我有一个父组件和子组件。每当子组件中的链接被点击时,我想执行作为props传递的父组件的点击处理程序。在点击处理程序中,我只想在父组件中递增一个整数状态。
问题是:每次点击单个链接(子组件)时,numCars
状态都会正确递增。例如,如果我点击“car1”链接5次,numCars
状态将增加到5。然而,如果我然后点击“car2”,numCars
状态会重置为0。如果我继续点击“car2”,numCars
将递增正常,直到我点击另一辆车。就像每个子组件都有自己的父组件一样。
为什么会发生这种情况?
export default function Garage() {
const [numCars, setNumCars] = useState(0);
const carHandleClick = (carName) => {
console.log("Clicked by " + carName);
setNumCars(numCars + 1);
}
const cars = [
{
name: "car1"
},
{
name: "car2"
},
{
name: "car3"
}
]
return (
<ul>
{cars.map((car) =>
<Car name={car.name} carHandleClick={carHandleClick}/>
)}
<ul>
);
}
export default function Car( {name, carHandleClick} ) {
return (
<li>
<Link to=... onClick={() => carHandleClick(name)}>
{name}
</Link>
</li>
)
}
英文:
I have a parent and child components. Whenever the Link in the child component is clicked, I want to execute the parent's click handler that is passed in as props. In the click handler, I simply want to increment an integer state in the parent component.
The issue: the numCars
state is correctly incremented for each single Link (child component) I click. For instance, if I click on the Link "car1" 5 times, the numCars
state is incremented to 5. However, if I then click on "car2", the numCars
state is reset back to 0. If I continue clicking "car2", numCars
is incremented properly, until I click on another car. It's as if each child has its own parent component.
Why is this happening?
export default function Garage() {
const [numCars, setNumCars] = useState(0);
const carHandleClick = (carName) => {
console.log("Clicked by " + carName);
setNumCars(numCars + 1);
}
const cars = [
{
name: "car1"
},
{
name: "car2"
},
{
name: "car3"
}
]
return (
<ul>
{cars.map((car) =>
<Car name={car.name} carHandleClick={carHandleClick}/>
}
<ul>
);
}
export default function Car( {name, carHandleClick} ) {
return (
<li>
<Link to=... onClick={() => carHandleClick(name)}
{name}
</Link>
</li>
)
}
答案1
得分: 1
carHandleClick = (carName) => {
setNumCars(prev => prev + 1);
}
或者使用带有 [numCars]
的 useCallback
钩子:
carHandleClick = useCallback((carName) => {
setNumCars(numCars + 1);
}, [numCars]);
更新:
问题与导航链接导致父组件卸载和重新挂载,因此其状态被重置有关。
处理此问题的一种方法是在顶层使用上下文:
export const MyContext = createContext();
const App = () => {
const [numCars, setNumCars] = useState(0);
const carHandleClick = (carName) => {
console.log("Clicked by " + carName);
setNumCars((prev) => prev + 1);
};
return (
<MyContext.Provider value={{ numCars, carHandleClick }}>
//...
</MyContext.Provider>
);
}
现在您只需从父组件和子组件中使用它:
import { MyContext } from "./App";
export default function Garage() {
const { carHandleClick, numCars } = useContext(MyContext);
//...
return (
<ul>
{cars.map((car) => (
<Car name={car.name} />
))}
</ul>
);
}
import { MyContext } from "./App";
function Car({ name }) {
const { carHandleClick, numCars } = useContext(MyContext);
//...
return (
<li>
<Link onClick={() => carHandleClick(name)}>{name}</Link>
</li>
);
}
了解更多关于 useContext 的信息。
英文:
carHandleClick = (carName) => {
setNumCars(prev => prev + 1);
}
you want always to use the functional form of the state setter if you want to update it based on its previous value
or a useCallback hook with [numCars]
:
carHandleClick = useCallback((carName) => {
setNumCars(numCars + 1);
},[numCars])
Update:
the issue was related to the fact navigate with the link unmounts and remounts the parent component so its state is reset.<br>
one way to handle this is to use a context in the top level:<br>
export const MyContext = createContext();
const App = () => {
const [numCars, setNumCars] = useState(0);
const carHandleClick = (carName) => {
console.log("Clicked by " + carName);
setNumCars((prev) => prev + 1);
};
return (
<MyContext.Provider value={{ numCars, carHandleClick }}>
//...
</MyContext.Provider>
);
}
now you juste consume it from both parent and child:
import { MyContext } from "./App";
export default function Garage() {
const { carHandleClick, numCars } = useContext(MyContext);
//...
return (
<ul>
{cars.map((car) => (
<Car name={car.name} />
))}
</ul>
);
}
import { MyContext } from "./App";
function Car({ name }) {
const { carHandleClick, numCars } = useContext(MyContext);
//...
return (
<li>
<Link onClick={() => carHandleClick(name)}>{name}</Link>
</li>
);
}
Learn more about useContext
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论