如何在路由不变时维护同一Modal组件的多层级钻取状态?
如何维护可钻取Modal的层级状态(无路由变化)
核心方案:用「状态栈」管理每一层Modal的状态
最直接的方式是维护一个栈结构的数组,每一层钻取的状态(当前展示的数据、层级标识等)都作为一个元素存入栈中:钻取时推入新状态,返回时弹出栈顶,始终用栈顶状态渲染当前Modal。
1. 定义栈状态
在控制Modal的父组件(或Modal内部)初始化栈状态,初始元素为第一层的列表数据:
import { useState } from 'react'; const ParentComponent = () => { // 初始栈:包含第一层的列表数据 const [modalStateStack, setModalStateStack] = useState([ { data: initialListData, level: 0 } ]); const [modalVisible, setModalVisible] = useState(true); // 当前展示的状态取栈最后一个元素 const currentState = modalStateStack[modalStateStack.length - 1];
2. 处理钻取逻辑
点击列表项的钻取箭头时,获取下一层数据并推入栈:
// 模拟获取下一层数据的接口请求 const fetchNextLevelData = async (itemId) => { const res = await fetch(`/api/get-next-level?id=${itemId}`); return res.json(); }; const handleDrillDown = async (item) => { const nextData = await fetchNextLevelData(item.id); // 有数据才推入栈 if (nextData.length > 0) { setModalStateStack(prevStack => [ ...prevStack, { data: nextData, level: prevStack.length } ]); } };
3. 处理返回逻辑
点击返回按钮时,若栈长度大于1(不是初始层),则移除栈顶元素:
const handleGoBack = () => { if (modalStateStack.length > 1) { // 保留栈中除最后一个元素外的所有内容 setModalStateStack(prevStack => prevStack.slice(0, -1)); } else { // 回到初始层后可以选择关闭Modal setModalVisible(false); } };
4. Modal渲染逻辑
基于当前栈顶状态渲染列表,根据栈长度判断是否显示返回按钮:
return ( <Modal visible={modalVisible} onCancel={() => setModalVisible(false)}> {/* 只有非初始层才显示返回按钮 */} {modalStateStack.length > 1 && ( <button onClick={handleGoBack} style={{ marginBottom: 16 }}> ← 返回上一层 </button> )} <ul> {currentState.data.map(item => ( <li key={item.id}> {item.name} {/* 有子数据才显示钻取箭头 */} {item.hasChildren && ( <span onClick={() => handleDrillDown(item)} style={{ marginLeft: 8, cursor: 'pointer' }}> → </span> )} </li> ))} </ul> </Modal> ); };
优化建议
- 状态持久化:如果需要刷新页面后恢复层级状态,可以把栈数据存在
localStorage中:
// 初始化时读取本地存储 const [modalStateStack, setModalStateStack] = useState(() => { const saved = localStorage.getItem('modalDrillStack'); return saved ? JSON.parse(saved) : [{ data: initialListData, level: 0 }]; }); // 栈更新时同步到本地存储 useEffect(() => { localStorage.setItem('modalDrillStack', JSON.stringify(modalStateStack)); }, [modalStateStack]);
- 避免重复请求:可以用一个Map缓存已请求过的节点数据,返回时直接读取缓存,减少接口调用:
const [dataCache, setDataCache] = useState(new Map()); const fetchNextLevelData = async (itemId) => { if (dataCache.has(itemId)) return dataCache.get(itemId); const res = await fetch(`/api/get-next-level?id=${itemId}`); const data = res.json(); setDataCache(prev => new Map(prev).set(itemId, data)); return data; };
其他思路(大型应用场景)
如果你的应用是多组件共享这个Modal状态,可以用Redux、Zustand等状态管理库,把栈状态放在全局store中,让相关组件直接订阅和修改栈数据,核心逻辑还是基于栈的推入/弹出。
内容的提问来源于stack exchange,提问作者vidhi
相关产品推荐
相关产品推荐

