React中多个相同组件的按钮点击时全部触发,如何实现仅触发点击的单个按钮?
解决React中多个按钮点击同步触发的问题
哈哈,这个问题我刚学React的时候也踩过一模一样的坑!核心原因很简单:你现在所有的按钮都共用了同一个show状态变量,不管点哪个按钮,都会修改这个全局的状态,导致所有依赖show的代码片段都跟着同步显示或隐藏。
下面给你两种简单的解决方案,选一种适合你的就行:
方案一:封装独立组件(推荐)
把每个带按钮和代码框的卡片部分抽成一个单独的组件,让每个组件自己管理自己的show状态,这样各个卡片之间的状态就完全独立了,互不影响。
示例代码:
// 新建一个独立的代码切换卡片组件 const CodeToggleCard = ({ title, IconComponent, contentComponent: Content, codeString }) => { // 每个组件自己维护show状态 const [show, setShow] = useState(false); const classes = useStyles(); // 如果你有自定义样式,保留这行 return ( <Box pb={2}> <Box align="left"> <h1>UI Elements</h1> </Box> <Card> <CardContent> <h2 align='Left'> {IconComponent && <IconComponent />} {title} </h2> <hr/> <Content /> </CardContent> </Card> <IconButton onClick={() => setShow(!show)} aria-label="Toggle code display" align="right" > <CodeIcon/> </IconButton> {show && ( <div> <Paper className={classes.paperColor}> <SyntaxHighlighter className={classes.paperColor} language="javascript" style={dracula} align="left" > {codeString} </SyntaxHighlighter> </Paper> </div> )} </Box> ); }; // 然后在父组件里多次使用这个组件 const ParentComponent = () => { return ( <Box align="center"> {/* 颜色卡片 */} <CodeToggleCard title="Colors" IconComponent={FormatColorFillIcon} contentComponent={App} codeString={yourColorCodeString} // 替换成你的颜色相关代码字符串 /> {/* 按钮卡片(假设你有对应的组件和代码) */} <CodeToggleCard title="Buttons" IconComponent={ButtonIcon} contentComponent={ButtonDemo} codeString={yourButtonCodeString} // 替换成你的按钮相关代码字符串 /> {/* 其他需要的卡片都这么加 */} </Box> ); };
这个方案的好处是代码复用性高,以后要加新的卡片直接调用组件就行,而且每个卡片的状态完全隔离,不会互相干扰。
方案二:用对象管理多个状态(不抽组件的情况下)
如果你不想新建组件,可以在父组件里用一个对象来存储每个卡片的显示状态,给每个卡片分配一个唯一的标识(比如标题或者id),点击按钮时只切换对应标识的状态。
示例代码:
const ParentComponent = () => { // 用对象存储每个卡片的显示状态,key是卡片的唯一标识 const [showStates, setShowStates] = useState({ colors: false, buttons: false, // 其他卡片的初始状态都在这里加 }); // 切换指定卡片的显示状态 const toggleCardShow = (cardKey) => { setShowStates(prevStates => ({ ...prevStates, [cardKey]: !prevStates[cardKey] })); }; const classes = useStyles(); return ( <Box align="center"> {/* 颜色卡片 */} <Box pb={2}> <Box align="left"> <h1>UI Elements</h1> </Box> <Card> <CardContent> <h2 align='Left'><FormatColorFillIcon/> Colors</h2> <hr/> <App/> </CardContent> </Card> <IconButton onClick={() => toggleCardShow('colors')} aria-label="Toggle code" align="right" > <CodeIcon/> </IconButton> {showStates.colors && ( <div> <Paper className={classes.paperColor}> <SyntaxHighlighter className={classes.paperColor} language="javascript" style={dracula} align="left" > {yourColorCodeString} </SyntaxHighlighter> </Paper> </div> )} </Box> {/* 按钮卡片 */} <Box pb={2}> <Box align="left"> <h1>UI Elements</h1> </Box> <Card> <CardContent> <h2 align='Left'><ButtonIcon/> Buttons</h2> <hr/> <ButtonDemo/> </CardContent> </Card> <IconButton onClick={() => toggleCardShow('buttons')} aria-label="Toggle code" align="right" > <CodeIcon/> </IconButton> {showStates.buttons && ( <div> <Paper className={classes.paperColor}> <SyntaxHighlighter className={classes.paperColor} language="javascript" style={dracula} align="left" > {yourButtonCodeString} </SyntaxHighlighter> </Paper> </div> )} </Box> </Box> ); };
这个方案不用改组件结构,只需要把原来的单个show状态改成对象,通过唯一key来控制每个卡片的显示,适合快速修改现有代码。
总结一下:React里状态是“自上而下”传递的,如果多个元素共用同一个状态,它们的行为就会同步。要让元素独立交互,要么给每个元素分配自己的状态(封装组件),要么用唯一标识来区分不同元素的状态~
内容的提问来源于stack exchange,提问作者Eugene Cabangon
相关产品推荐
相关产品推荐

