You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:34:55