React类转函数组件:如何共享单个对话框加载多子组件不同数据
当然可以复用单个对话框组件!这种优化不仅能减少冗余的DOM节点,还能让状态管理更集中,完全是这类场景的最佳实践。我来一步步教你怎么改造:
核心思路
把原本分散在每个WorkoutCard里的EditWindow移到父仪表盘组件中,由父组件统一控制对话框的显示/隐藏状态,以及当前要编辑的训练数据。子组件只需要负责触发"打开对话框"的动作,并把对应的数据传递给父组件即可。
1. 改造父组件(仪表盘)
添加控制对话框的状态,把EditWindow移到父组件,同时给子组件传递打开对话框的回调:
constructor(props) { super(props); this.state = { workoutData: [], // 新增对话框控制状态 isDialogOpen: false, currentEditWorkout: null }; } // 打开对话框的方法,接收要编辑的数据 openEditDialog = (workoutData) => { this.setState({ isDialogOpen: true, currentEditWorkout: workoutData }); }; // 关闭对话框的方法 closeEditDialog = () => { this.setState({ isDialogOpen: false, currentEditWorkout: null }); }; // 更新数据后自动关闭对话框(可选,根据你的业务逻辑调整) updateWorkouts = (updatedData) => { // 你的原有更新逻辑... // 更新完成后关闭对话框 this.closeEditDialog(); }; public render() { return( <div> <AddWorkoutButton updateWorkout={this.updateWorkouts} isDarkMode={this.props.isDarkMode}/> {/* 复用的单个对话框,现在放在父组件里 */} <EditWindow openEditWindow={this.state.isDialogOpen} handleClose={this.closeEditDialog} updateWorkout={this.updateWorkouts} isDarkMode={this.props.isDarkMode} workoutData={this.state.currentEditWorkout} /> <div className="container" style={{paddingBottom: '3rem'}}> <div className="row"> {this.state.workoutData.map((workoutData: object, index: number) => ( <div className="col-md-6 col-lg-4" key={index}> {/* 子组件不再带对话框,改为传递打开回调 */} <WorkoutCard workoutData={workoutData} openEditDialog={this.openEditDialog} isDarkMode={this.props.isDarkMode} /> </div> ))} </div> </div> </div> ); }
2. 改造子组件(WorkoutCard)
移除自带的EditWindow,添加触发打开对话框的按钮,调用父组件传递的回调:
public render() { return( <div> <Card className={classes.card}> {/* 你的卡片原有内容... */} {/* 新增编辑按钮,点击时把当前卡片的数据传给父组件打开对话框 */} <Button onClick={() => this.props.openEditDialog(this.props.workoutData)} variant="outlined" color="primary" style={{marginTop: '1rem'}} > 编辑训练 </Button> </Card> </div> ) }
3. 调整EditWindow组件(可选优化)
因为现在是父组件传递数据,你可以在函数组件里用useEffect同步传入的编辑数据到本地状态,方便表单编辑:
import { useEffect, useState } from 'react'; const EditWindow = (props) => { const [localWorkoutData, setLocalWorkoutData] = useState({}); // 当父组件传递的workoutData变化时,更新本地编辑状态 useEffect(() => { if (props.workoutData) { setLocalWorkoutData({...props.workoutData}); } }, [props.workoutData]); return ( <div> <Dialog maxWidth={"md"} fullWidth open={props.openEditWindow} TransitionComponent={Transition} onClose={props.handleClose} aria-labelledby="alert-dialog-slide-title" aria-describedby="alert-dialog-slide-description" > {/* 对话框内容示例,使用本地状态进行编辑 */} <DialogTitle id="alert-dialog-slide-title">编辑训练计划</DialogTitle> <DialogContent> <TextField label="训练名称" value={localWorkoutData.name || ''} onChange={(e) => setLocalWorkoutData(prev => ({...prev, name: e.target.value}))} fullWidth margin="normal" /> {/* 其他表单字段... */} </DialogContent> <DialogActions> <Button onClick={props.handleClose}>取消</Button> <Button onClick={() => props.updateWorkout(localWorkoutData)}>保存修改</Button> </DialogActions> </Dialog> </div> ); }; export default EditWindow;
为什么这么做?
- 性能提升:原本每个卡片都渲染一个对话框,现在只渲染一个,DOM节点数量大幅减少,尤其是卡片多的时候效果明显。
- 状态集中:所有对话框相关的状态都在父组件管理,避免了多个子组件各自维护状态的混乱。
- 扩展性强:如果以后要做"新增训练"功能(用同一个对话框),只需要在父组件里加一个打开对话框的方法,传入空对象即可,完全复用现有组件。
内容的提问来源于stack exchange,提问作者Hilkjh
相关产品推荐
相关产品推荐

