React Router v6点击按钮无法渲染子页面(Typescript)
React路由跳转失败问题解决
我开发了一个基于TypeScript的React应用,首页是App.tsx。用户输入邮箱后点击“Let's get started”按钮,预期要把邮箱参数传给GetStartedPage组件并渲染该页面,但点击按钮后没有任何跳转或页面渲染,只有App.tsx里的日志能输出。
我的错误逻辑是:点击按钮时调用handleCreateProfileClick()函数,在函数里直接返回<GetStartedPage inputEmail={email} />组件。虽然已经在AppRouter.tsx里配置了包含GetStartedPage的路由规则,但不知道为什么直接返回组件无法触发页面渲染。
核心问题分析
React的点击事件处理器不能通过返回组件来触发页面渲染/跳转,事件处理器的返回值会被忽略。要实现页面跳转,必须使用react-router-dom提供的导航API。另外入口文件没有正确使用路由配置,导致路由规则根本没生效。
分步修复方案
1. 修复入口文件index.tsx
当前入口直接渲染App组件,没有使用AppRouter,导致路由配置完全没生效。修改为渲染AppRouter:
import { createRoot } from 'react-dom/client'; import { Provider } from 'react-redux'; import store from './redux/store'; import AppRouter from './AppRouter'; // 导入AppRouter const container = document.getElementById('root'); if (container) { const root = createRoot(container); root.render( <Provider store={store}> <AppRouter /> </Provider> ); } else { console.error('Container element not found!'); }
2. 修改App.tsx,使用路由导航代替返回组件
在App组件中通过useNavigate钩子获取导航方法,点击按钮时调用navigate跳转,同时把邮箱参数通过路由状态传递:
import React, { useState, useEffect, ReactNode } from 'react'; import signinIcon from 'icons/signin_icon.png'; import './App.css'; import { useNavigate } from 'react-router-dom'; // 导入useNavigate const App = () : ReactNode => { const [showSidePanel, setShowSidePanel] = useState(false); const [email, setEmail] = useState(''); const navigate = useNavigate(); // 获取导航函数 const handleEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => { setEmail(event.target.value); }; const handleCreateProfileClick = () => { if (!email) { alert('Please enter your email'); return; } console.log("About to navigate from handleCreateProfile in App.tsx"); // 跳转到/create-profile路由,把邮箱放在state里 navigate('/create-profile', { state: { email } }); }; const handleSignInClick = () => { // 同样用navigate跳转,不要返回组件 navigate('/sign-in'); }; const handleResize = () => { if (window.innerWidth > 600) { setShowSidePanel(false); } }; useEffect(() => { window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); }; }, []); return ( <div className="App"> <div id="page-container"> <div className="menu"> <div className="menu-item sign-up" onClick={handleSignInClick}> <img src={signinIcon} alt="Sign in" className="signin"/> <span className="sign-up-text">Sign in</span> </div> </div> <div className="container"> <div className="left-content"> <div className="email-form"> <input type="email" placeholder="Email address" onChange={handleEmailChange} value={email} id="email-input" required /> <button className="lets-go-button" onClick={handleCreateProfileClick}> Let's get started </button> </div> <div className="sign-in"> Already joined? <u> {/* 阻止a标签默认跳转,用onClick处理 */} <a href="/signin" onClick={(e) => { e.preventDefault(); handleSignInClick(); }}>Sign in</a> </u>. </div> </div> </div> </div> </div> ); }; export default App;
3. 修正AppRouter.tsx的路由配置
不需要给AppRouter传递email参数,邮箱参数通过路由状态传递,GetStartedPage直接从路由状态中获取:
import React from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import App from './App'; import GetStartedPage from './GetStartedPage'; import SignInPage from './SignInPage'; // 导入SignInPage const AppRouter = () => { return ( <Router> <Routes> <Route path="/" element={<App />} /> <Route path="/create-profile" element={<GetStartedPage />} /> <Route path="/sign-in" element={<SignInPage />} /> </Routes> </Router> ); }; export default AppRouter;
4. 修改GetStartedPage.tsx获取路由状态中的邮箱
使用useLocation钩子获取路由状态里的邮箱:
import React, { useState, useEffect } from 'react'; import axios from 'axios'; import { useLocation } from 'react-router-dom'; // 导入useLocation const GetStartedPage = () => { const [email, setEmail] = useState(''); const location = useLocation(); // 获取路由位置对象 useEffect(() => { // 从路由state中取出邮箱 if (location.state?.email) { setEmail(location.state.email); } }, [location.state]); console.log("Currently in Create profile page"); // 修正async函数包裹await逻辑 const createProfile = async () => { try { await axios.post('/createProfile', { email /* 其他用户数据 */ }); alert('Profile created successfully'); } catch (error) { console.error('Error creating profile:', error); alert('Error creating profile'); } }; return ( <div> <h1>Get Started</h1> <p>Email: {email}</p> {/* 其他页面元素 */} </div> ); }; export default GetStartedPage;
关键知识点总结
- React事件处理器的返回值不会影响组件渲染,必须通过状态更新或路由导航来改变页面内容。
- 使用
react-router-dom的useNavigate实现路由跳转,useLocation获取路由状态参数。 - 入口文件必须渲染包含路由配置的组件,否则路由规则不会生效。
内容的提问来源于stack exchange,提问作者fibonaccilinguine
相关产品推荐
相关产品推荐

