React复用组件实现点击单个盒子高亮(其余恢复默认样式)的解决方案
Got it, let's break down why your current code is making all boxes turn red when you click any one of them, and fix it while sticking to your requirements (single state, no changes to existing property names).
The Root Problem
Right now, your Box component checks if color is any of the three box identifiers (firstBox, secondBox, thirdBox). That means whenever you set color to any of those values, every box will match the condition and get the active class. That's why all boxes turn red—they're all passing the same check!
The Solution
We just need to give each Box a unique identifier so it can check if the current color state matches its own identifier, not just any box's. We'll add a new prop (we'll call it boxKey) to each Box instance, and update the class condition to compare color against this key. This keeps your existing setColor and color props intact, and uses only one state variable.
Here's the revised code:
Updated JavaScript
const {useState} = React; const App = () => { const [color, setColor] = useState(""); // Optional: Simplify click handlers into one function to cut down repetition const setBoxColor = (boxId) => { setColor(boxId); }; return ( <div className="container"> <Box setColor={() => setBoxColor("firstBox")} color={color} boxKey="firstBox" /> <Box setColor={() => setBoxColor("secondBox")} color={color} boxKey="secondBox" /> <Box setColor={() => setBoxColor("thirdBox")} color={color} boxKey="thirdBox" /> {/* If you prefer keeping your original separate functions, use this instead: <Box setColor={firstBox} color={color} boxKey="firstBox" /> <Box setColor={secondBox} color={color} boxKey="secondBox" /> <Box setColor={thirdBox} color={color} boxKey="thirdBox" /> */} </div> ); } const Box = ({ setColor, color, boxKey }) => { return ( <div onClick={setColor} className={`box ${ color === boxKey ? "active" : "" } `}></div> ); }; ReactDOM.createRoot( document.getElementById("root") ).render( <App/> );
CSS (No Changes Needed)
body { min-height: 100vh; display: flex; align-items: center; justify-content: center; } .container { display: flex; gap: 2rem; } .box { width: 250px; height: 250px; background: lightblue; } .active { background: red; }
HTML (No Changes Needed)
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react-dom.development.js"></script>
How It Works
- Each
Boxnow has a uniqueboxKeythat matches the value we set in thecolorstate when it's clicked. - When you click a box, the
colorstate is updated to that box'sboxKey. - The
Boxcomponent only applies theactiveclass ifcolorequals its ownboxKey—so only the clicked box turns red, and all others stay (or revert to) light blue.
This solution sticks strictly to your requirements: we're using only one state variable, and we didn't modify the names of your existing setColor and color props.
内容的提问来源于stack exchange,提问作者Adrian

