无需React Router的React页面切换方法探讨及替代方案问询
无需路由库的页面/模式切换方案探讨
我已经针对简单应用(最多3个模式/页面)测试了两种页面切换方式,目前还在学习阶段,主要练习使用useState,部分场景会用到useEffect。想了解有没有其他不用路由库的页面/模式切换方法。
实践案例1
目标
打造通用Modal组件,页面结构放在顶层组件里。这个Modal带关闭按钮,能渲染传入的子组件,数据上下文由父组件维护。Add和Edit各自有独立状态,暂时不考虑关闭Modal再打开后的数据保留问题。
缺点
这种方法里有太多isShow类的判断,理想状态是所有状态都集中在父组件;如果页面/模式超过3个,switch语句会变得很繁琐。
案例代码
import { useState } from 'react'; // 带显示状态、关闭按钮和子组件的简易Modal const Modal = ({ isShown, onClose, children }) => { return ( <> {isShown && ( <div className='modal-overlay'> <div className='modal'> {children} <button onClick={onClose}>X</button> </div> </div> )} </> ) } // 简易添加事件组件,通过onSubmit回调向父组件传递数据 const AddEvent = ({ onSubmit }) => { const [name, setName] = useState('') console.log('渲染添加事件组件') return ( <> <div> <p>添加事件模式:</p> <input type='text' name='name' placeholder='输入名称' onChange={(e) => setName(e.target.value)} value={name} /> <button id='some' onClick={() => onSubmit(name)}> 向父组件传递名称 </button> </div> </> ) } // 简易编辑事件组件,从父组件获取原始数据,通过onSubmit回调传递修改后的数据 const EditEvent = ({ originalData, onSubmit }) => { const [name, setName] = useState(originalData) console.log('渲染编辑事件组件') return ( <> <div> <p>编辑事件模式:</p> <input type='text' name='name' placeholder='输入名称' onChange={(e) => setName(e.target.value)} value={name} /> <button id='some' onClick={() => onSubmit(name)}> 向父组件传递数据 </button> </div> </> ) } // 主应用组件:管理Modal显示状态、数据和当前步骤(添加/编辑) export default function App() { const [showModal, toggleShowModal] = useState(false) const [parentData, setparentData] = useState('') const [step, setStep] = useState({ add: false, edit: false }) // 切换事件模式的核心函数 const toggleEventMode = (e) => { console.log('切换模式') switch (e.target.name) { case 'add': setStep({ add: true, edit: false }) toggleShowModal(true) break case 'edit': setStep({ add: false, edit: true }) toggleShowModal(true) break } } return ( <> <h3>点击添加事件创建内容,之后可以编辑</h3> <Modal isShown={showModal} onClose={() => toggleShowModal(false)}> {step.add && ( <AddEvent onSubmit={(dataFromAddEvent) => setparentData(dataFromAddEvent)} /> )} {step.edit && ( <EditEvent onSubmit={(dataFromEditEvent) => setparentData(dataFromEditEvent)} originalData={parentData} /> )} </Modal> <div className='card'> <button name='add' onClick={(e) => toggleEventMode(e)}> 添加事件 </button> <button name='edit' onClick={(e) => toggleEventMode(e)}> 编辑事件 </button> </div> </> ) }
其他无需路由库的页面/模式切换方案
1. 字符串/枚举类型管理当前视图
把原来的多布尔值状态改成单个字符串状态,直接标记当前激活的视图名称,简化判断逻辑,扩展更方便:
import { useState } from 'react'; // ...Modal、AddEvent、EditEvent组件保持不变 export default function App() { const [showModal, toggleShowModal] = useState(false) const [parentData, setparentData] = useState('') // 用字符串标记当前视图:'add'/'edit'/null const [currentView, setCurrentView] = useState(null) // 切换模式函数简化,无需switch const toggleEventMode = (view) => { setCurrentView(view) toggleShowModal(true) } return ( <> <h3>点击添加事件创建内容,之后可以编辑</h3> <Modal isShown={showModal} onClose={() => { toggleShowModal(false) setCurrentView(null) }} > {currentView === 'add' && <AddEvent onSubmit={setparentData} />} {currentView === 'edit' && <EditEvent originalData={parentData} onSubmit={setparentData} />} </Modal> <div className='card'> <button onClick={() => toggleEventMode('add')}>添加事件</button> <button onClick={() => toggleEventMode('edit')}>编辑事件</button> </div> </> ) }
2. 组件映射表
将所有可切换的组件存入一个对象,通过当前视图名称直接索引渲染,彻底消除条件判断:
import { useState } from 'react'; // ...Modal、AddEvent、EditEvent组件保持不变 export default function App() { const [showModal, toggleShowModal] = useState(false) const [parentData, setparentData] = useState('') const [currentView, setCurrentView] = useState(null) // 组件映射表:键为视图名称,值为对应的组件实例 const viewComponents = { add: <AddEvent onSubmit={setparentData} />, edit: <EditEvent originalData={parentData} onSubmit={setparentData} /> } return ( <> <h3>点击添加事件创建内容,之后可以编辑</h3> <Modal isShown={showModal} onClose={() => { toggleShowModal(false) setCurrentView(null) }} > {/* 直接通过映射表渲染当前视图 */} {viewComponents[currentView]} </Modal> <div className='card'> <button onClick={() => {setCurrentView('add'); toggleShowModal(true)}}>添加事件</button> <button onClick={() => {setCurrentView('edit'); toggleShowModal(true)}}>编辑事件</button> </div> </> ) }
新增模式时只需在viewComponents中添加一行,完全无需修改渲染逻辑。
3. 无Modal的页面切换(状态驱动条件渲染)
如果是普通页面切换而非Modal弹窗,直接用状态控制整个页面区域的渲染:
import { useState } from 'react'; const HomePage = () => <h2>首页</h2>; // ...AddEvent、EditEvent组件保持不变 export default function App() { const [currentView, setCurrentView] = useState('home') return ( <div className='app-container'> <nav className='nav-bar'> <button onClick={() => setCurrentView('home')}>首页</button> <button onClick={() => setCurrentView('add')}>添加事件</button> <button onClick={() => setCurrentView('edit')}>编辑事件</button> </nav> <main className='content-area'> {currentView === 'home' && <HomePage />} {currentView === 'add' && <AddEvent onSubmit={(data) => console.log(data)} />} {currentView === 'edit' && <EditEvent originalData='测试数据' onSubmit={(data) => console.log(data)} />} </main> </div> ) }
4. useReducer管理复杂状态
当模式数量多、状态逻辑复杂时,用useReducer统一管理视图切换和数据状态,让组件逻辑更清晰:
import { useReducer } from 'react'; // 初始状态 const initialState = { showModal: false, currentView: null, parentData: '' }; // 状态更新 reducer function viewReducer(state, action) { switch (action.type) { case 'OPEN_VIEW': return { ...state, showModal: true, currentView: action.payload }; case 'CLOSE_MODAL': return { ...state, showModal: false, currentView: null }; case 'UPDATE_DATA': return { ...state, parentData: action.payload }; default: return state; } } // ...Modal、AddEvent、EditEvent组件保持不变 export default function App() { const [state, dispatch] = useReducer(viewReducer, initialState); return ( <> <h3>点击添加事件创建内容,之后可以编辑</h3> <Modal isShown={state.showModal} onClose={() => dispatch({ type: 'CLOSE_MODAL' })} > {state.currentView === 'add' && ( <AddEvent onSubmit={(data) => dispatch({ type: 'UPDATE_DATA', payload: data })} /> )} {state.currentView === 'edit' && ( <EditEvent originalData={state.parentData} onSubmit={(data) => dispatch({ type: 'UPDATE_DATA', payload: data })} /> )} </Modal> <div className='card'> <button onClick={() => dispatch({ type: 'OPEN_VIEW', payload: 'add' })}>添加事件</button> <button onClick={() => dispatch({ type: 'OPEN_VIEW', payload: 'edit' })}>编辑事件</button> </div> </> ) }
所有状态更新逻辑集中在reducer中,便于维护和扩展复杂的视图切换规则。
内容的提问来源于stack exchange,提问作者Varun D
相关产品推荐
相关产品推荐

