React Hooks最佳实践:多模态框/弹窗顺序切换的精简实现方案
React多模态框链路的优化方案
核心优化思路
不用为每个模态框单独维护开关状态,仅用1个状态存储当前激活的模态框索引,所有模态框按链路顺序存入数组,通过索引匹配渲染对应模态框,统一封装前进、后退、关闭的通用方法。
具体实现步骤
1. 重构父组件代码
import { useState } from 'react'; import Dialogue1 from './Dialogue1'; import Dialogue2 from './Dialogue2'; import Dialogue3 from './Dialogue3'; // 剩余22个模态框按顺序引入 // 按链路顺序把所有模态框组件存入数组 const dialogueList = [Dialogue1, Dialogue2, Dialogue3, /* 剩余22个组件按顺序填入 */]; const BasicPage = (props) => { // 初始值为null表示无模态框打开,值为当前展示模态框的数组索引 const [currentDialogueIndex, setCurrentDialogueIndex] = useState(null); const openFirstDialogue = () => setCurrentDialogueIndex(0); const closeAll = () => setCurrentDialogueIndex(null); const goPrev = () => { setCurrentDialogueIndex(prev => prev > 0 ? prev - 1 : null); }; const goNext = () => { setCurrentDialogueIndex(prev => prev < dialogueList.length - 1 ? prev + 1 : null); }; // 支持跳转到指定位置的模态框,满足非相邻跳转需求 const jumpToDialogue = (index) => { if (index >= 0 && index < dialogueList.length) setCurrentDialogueIndex(index); }; const CurrentDialogue = dialogueList[currentDialogueIndex]; return ( <> <button onClick={openFirstDialogue}>Show dialogue</button> {CurrentDialogue && ( <CurrentDialogue goPrev={goPrev} goNext={goNext} closeAll={closeAll} jumpToDialogue={jumpToDialogue} /> )} </> ); }; export default BasicPage;
2. 改造子模态框代码
可以把多个模态框重复的表单逻辑抽成自定义Hook复用,进一步减少冗余代码:
import React, { useState } from "react" import { Field, Form } from "react-jsonschema-form-validation"; import Submit from "./components/Submit"; const fieldName = 'referred'; const schema = { type: 'object', required: [fieldName], }; // 抽离通用表单Hook,所有模态框可复用 const useDialogueForm = (schema) => { const [formData, setFormData] = useState(); const [success, setSuccess] = useState(false); const handleChange = (newData) => { setFormData(newData); setSuccess(false); }; const handleSubmit = (afterSubmit) => { setSuccess(true); console.log("Data submitted: ", formData?.[fieldName]); afterSubmit?.(); }; return { formData, success, handleChange, handleSubmit }; }; const Dialogue2 = (props) => { const { goPrev, goNext } = props; const { formData, success, handleChange, handleSubmit } = useDialogueForm(schema); return ( <Form data={formData} onChange={handleChange} onSubmit={() => handleSubmit(goNext)} schema={schema} > <h1>Dialogue 2</h1> <p>Choose yes or no</p> <div> <Field type="radio" name={fieldName} id="yes" value={"yes"} /> <label htmlFor={"yes"}>Yes</label> <Field type="radio" name={fieldName} id="no" value={"no"} /> <label htmlFor={"no"}>No</label> </div> <button onClick={goPrev}>BACK</button> <Submit success={success} text={'NEXT'} /> </Form> ) } export default Dialogue2
方案优势
- 状态从25个缩减为1个,父组件代码量减少80%以上,新增模态框只需往
dialogueList数组追加组件即可,无需修改其他逻辑 - 子模态框无需接收定制化的开关参数,通用方法复用,传参冗余彻底解决
- 通用逻辑抽成Hook后,后续迭代修改只需修改Hook即可,无需逐个调整25个模态框的代码
内容的提问来源于stack exchange,提问作者cannon303
相关产品推荐
相关产品推荐

