React组件间传递setFruits:实现点击水果递减计数器的方法
问题与代码修复
需求:点击水果名称时,让计数器数值减1,同时需了解如何从App组件将setFruits传递给FruitsCounter组件并正确使用。
原代码
App.js
import Fruits from "./Fruits"; import FruitsCounter from "./FruitsCounter"; import React, {useState} from "react"; function App() { const [fruits, setFruits] = useState([ {fruitName: 'apple', id: 1}, {fruitName: 'apple', id: 2}, {fruitName: 'plum', id: 3}, ]); const handleClick = () => { setFruits = fruits.length - 1; } return ( <div className="App"> <h1>Where should the state go?</h1> <Fruits name={fruits} set={ handleClick}/> <FruitsCounter name={fruits} set={ handleClick}/> </div> ); } export default App;
Fruits.js
import React from "react"; function Fruits(props) { return ( <div> {props.name.map(f => <p key={f.id} onClick={props.set}>{f.fruitName}</p>)} </div> ) } export default Fruits
FruitsCounter.js
function FruitsCounter(props) { return ( <h2>Total fruits: {props.name.length}</h2> ) } export default FruitsCounter;
解决方案
1. 修正App.js的状态更新逻辑与props传递
setFruits是React状态更新函数,不能直接赋值,需传入新数组;同时要通过点击事件传递水果ID来精准移除元素,还要给子组件传递语义化的props:
import Fruits from "./Fruits"; import FruitsCounter from "./FruitsCounter"; import React, {useState} from "react"; function App() { const [fruits, setFruits] = useState([ {fruitName: 'apple', id: 1}, {fruitName: 'apple', id: 2}, {fruitName: 'plum', id: 3}, ]); // 接收水果ID,返回移除该ID后的新数组 const handleFruitRemove = (fruitId) => { setFruits(prevFruits => prevFruits.filter(fruit => fruit.id !== fruitId)); } return ( <div className="App"> <h1>Where should the state go?</h1> <Fruits fruits={fruits} onFruitClick={handleFruitRemove}/> {/* 直接将setFruits作为props传给FruitsCounter */} <FruitsCounter fruits={fruits} setFruits={setFruits}/> </div> ); } export default App;
2. 修改Fruits.js传递点击的水果ID
点击水果时,把当前水果的ID传给父组件的事件处理函数:
import React from "react"; function Fruits(props) { return ( <div> {props.fruits.map(f => ( <p key={f.id} onClick={() => props.onFruitClick(f.id)}> {f.fruitName} </p> ))} </div> ) } export default Fruits
3. 在FruitsCounter中使用setFruits(可选)
如果需要让计数器也能触发状态修改(比如点击计数器减少最后一个水果),可以这样写:
function FruitsCounter(props) { const handleCounterClick = () => { // 移除最后一个水果 props.setFruits(prevFruits => prevFruits.slice(0, -1)); } return ( <h2 onClick={handleCounterClick} style={{cursor: 'pointer'}}> Total fruits: {props.fruits.length} </h2> ) } export default FruitsCounter;
关键说明
- 状态更新必须使用函数式写法
setFruits(prevFruits => ...),确保拿到最新的状态值,避免闭包问题。 - 传递
setFruits给子组件只需在App的JSX中直接传入,子组件通过props.setFruits调用并传入新的状态数组即可。 - 语义化的props命名(比如
fruits代替name,onFruitClick代替set)能大幅提升代码可读性。
内容的提问来源于stack exchange,提问作者Kazi Arifin Islam
相关产品推荐
相关产品推荐

