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

React中使用Material UI Link跳转至其他组件的实现方法

问题根因

你的代码存在两个核心错误,直接导致路由跳转无法生效:

  • 错误放置了BrowserRouter:react-router-dom要求应用内所有路由相关组件必须包裹在同一个BrowserRouter实例下,你单独给注册页路由包了一层独立的BrowserRouter,和登录页不在同一个路由上下文里,跳转时根本匹配不到对应的路由规则。
  • 注册入口的MUI Link未对接路由:你当前写的注册跳转Link的href指向外部地址,既没有绑定react-router-dom的客户端路由跳转能力,也没有指向你定义的/register路径。
修复步骤
  1. 把根级BrowserRouter提到应用最外层(通常是App.jsx文件),包裹所有页面组件,不要在单个业务组件里单独嵌套BrowserRouter。
  2. 删除你当前写的内嵌式Register路由组件,把登录、注册的路由规则统一放在根路由表中配置。
  3. 注册入口的MUI Link通过component属性绑定为RouterLink,添加to属性指向/register路径,替换掉原来的外部href配置。
修正后的代码示例

首先是根组件App.jsx的路由配置,这里统一放置全局Router和路由表:

// App.jsx
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import LoginCard from './LoginCard';
import RegisterPage from './Register';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* 登录页路由 */}
        <Route path="/login" element={<LoginCard />} />
        {/* 注册页路由 */}
        <Route path="/register" element={<RegisterPage />} />
        {/* 未匹配路径默认重定向到登录页 */}
        <Route path="*" element={<Navigate to="/login" replace />} />
      </Routes>
    </BrowserRouter>
  )
}

export default App;

然后是修正后的LoginCard组件代码,删除多余的内嵌路由配置,修正跳转Link的写法:

import React, { useState } from 'react';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline';
import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Grid from '@mui/material/Grid';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import Link from '@mui/material/Link';
// 引入react-router的Link组件,重命名避免和MUI Link命名冲突
import { Link as RouterLink } from "react-router-dom";

function LoginCard({ Login, error }) {
  const [details, setDetails] = useState({ username: "", password: "" })

  const onFormSubmit = (e) => {
    e.preventDefault();
    Login(details);
  }

  const theme = createTheme();
  function Copyright(props) {
    return (
      <Typography variant="body2" color="text.secondary" align="center" {...props}>
        {'Copyright © '}
        <Link color="inherit" href="/">
          Fiin Frisører
        </Link>{' '}
        {new Date().getFullYear()}
        {'.'}
      </Typography>
    );
  }

  return(
    <ThemeProvider theme={theme}>
      <Container component="main" maxWidth="xs">
        <CssBaseline />
        <Box
          sx={{
            marginTop: 8,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
          }}
        >
          <Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
          </Avatar>
          <Typography component="h1" variant="h5">
            Sign in
          </Typography>
          <Box component="form" onSubmit={onFormSubmit} noValidate sx={{ mt: 1 }}>
            <TextField
              margin="normal"
              required
              fullWidth
              id="username"
              label="Username"
              name="username"
              onChange={e=> setDetails({...details, username: e.target.value})}
            />
            <TextField
              margin="normal"
              required
              fullWidth
              name="password"
              label="Password"
              type="password"
              id="password"
              onChange={e=> setDetails({...details, password: e.target.value})}
            />
            <FormControlLabel
              control={<Checkbox value="remember" color="primary" />}
              label="Remember me"
            />
            <Button
              type="submit"
              fullWidth
              variant="contained"
              sx={{ mt: 3, mb: 2 }}
            >
              Sign In
            </Button>
            <Grid container>
              <Grid item xs>
                <Link href="#" variant="body2">
                  Forgot password?
                </Link>
              </Grid>
              <Grid item>
                {/* 绑定路由组件,指定跳转路径 */}
                <Link 
                  component={RouterLink}
                  to="/register"
                  variant="body2"
                >
                 Don't have an account yet?
                </Link>
              </Grid>
            </Grid>
          </Box>
        </Box>
        <Copyright sx={{ mt: 8, mb: 4 }} />
      </Container>
    </ThemeProvider>
  );
};

export default LoginCard;
注意事项
  • 整个应用只需要在最顶层放置一次BrowserRouter即可,多个独立的Router实例会造成路由上下文隔离,导致跳转、参数获取等路由相关功能全部失效。
  • MUI的Link本质是样式组件,要实现SPA无刷新路由跳转,必须通过component属性将底层渲染元素替换为react-router-dom的RouterLink,再通过to属性指定路由路径,直接写href会触发浏览器整页刷新,不符合单页应用的路由预期。

内容的提问来源于stack exchange,提问作者Alexander Brandhaug

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 06:33:21