React:当输入一个字符时,输入框会失去焦点。

huangapple go评论66阅读模式
英文:

React: Input loses focus a character is typed,

问题

尝试使用React进行开发。

我创建了一个登录页面,使用MUI、formik和yup作为输入字段的电子邮件和密码。但是,每当我尝试在输入一个字符后输入任何文本时,输入框就会失去焦点。其他功能都按预期工作。

如果我将这些代码移动到app.js中,那么就没有问题,但是将其移回login.jsx似乎根本不起作用。

以下是我的代码:

app.js

import {
  Navigate,
  RouterProvider,
  createBrowserRouter,
} from "react-router-dom";
import { ColorModeContext, useMode } from "./theme";
import Login from "./pages/login/Login";
import { useContext, useState } from "react";
import { AuthContext } from "./context/AuthContext";
import { Box, CssBaseline, ThemeProvider } from "@mui/material";
import Home from "./pages/home/Home";
import ErrorPage from "./pages/error/Error";
import SidebarComponent from "./components/sidebar/Sidebar";
import Register from "./pages/register/Register";

function App() {
  const currentUser = useContext(AuthContext);
  const [theme, colorMode] = useMode();

  const Layout = () => {
    <Box
      sx={{
        display: "flex",
        height: "100%",
        minHeight: "400px",
      }}
    >
      <SidebarComponent />

      <main>rtest</main>
    </Box>;
  };

  const ProtectedRoute = ({ children }) => {
    if (!currentUser.user) {
      return <Navigate to="/login" />;
    }

    return children;
  };

  const router = createBrowserRouter([
    {
      path: "/",
      element: (
        <ProtectedRoute>
          <Layout />
        </ProtectedRoute>
      ),
      children: [
        {
          path: "/",
          element: <Home />,
        },
      ],
      errorElement: <ErrorPage />,
    },
    {
      path: "/login",
      element: <Login />,
    },
    {
      path: "/login",
      element: <Register />,
    },
  ]);

  return (
    <ColorModeContext.Provider value={colorMode}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <div className="App">
          <RouterProvider router={router} />
        </div>
      </ThemeProvider>
    </ColorModeContext.Provider>
  );
}

export default App;

Login.jsx

import Logo from "../../assets/backticklogo.svg";
import { Link, useNavigate } from "react-router-dom";
import { useContext, useEffect, useState } from "react";
import { AuthContext } from "../../context/AuthContext";
import apiClient from "../../services/api";
import { Box, Button, Stack, TextField, Typography } from "@mui/material";
import styled from "@emotion/styled";
import { useFormik } from "formik";
import * as yup from "yup";

const validationSchema = yup.object({
  email: yup
    .string("Enter your email")
    .email("Enter a valid email")
    .required("Email is required"),
  password: yup
    .string("Enter your password")
    .min(8, "Password should be of minimum 8 characters length")
    .required("Password is required"),
});

const Login = () => {
  const localplainTextToken = localStorage.getItem("plainTextToken") || null;
  const [isAuth, setIsAuth] = useState(localStorage.getItem("isAuth") || null);

  const [plainTextToken, setplainTextToken] = useState(localplainTextToken);
  const remember = true;
  const navigate = useNavigate();
  const { user, dispatch } = useContext(AuthContext);

  useEffect(() => {
    isAuth && navigate("/");
  }, [isAuth]);

  const handleUpdateUser = (userInfo) => {
    console.log(userInfo);
    dispatch({ type: "LOGIN", payload: userInfo });
    localStorage.setItem("user", JSON.stringify(userInfo));
    localStorage.setItem("isAuth", true);
    setIsAuth(true);
  };

  const formik = useFormik({
    initialValues: {
      email: "",
      password: "",
    },
    validationSchema: validationSchema,
    onSubmit: async (values) => {
      // alert(JSON.stringify(values, null, 2));
      try {
        await apiClient
          .post("login", {
            email: values.email,
            password: values.password,
          })
          .then((res) => {
            console.log(res);
            localStorage.setItem("plainTextToken", res.data.plainTextToken);
            setplainTextToken(res.data.plainTextToken);
            return res.data;
          })
          .then(async (data) => {
            try {
              let user = await apiClient.get(`user/${data.user_id}`, {
                headers: {
                  Authorization: `Bearer ${data.plainTextToken}`,
                  Accept: "application/json",
                },
              });
              console.log(user);
              handleUpdateUser(user.data);
              // navigate("/");
            } catch (error) {}
          });
      } catch (error) {
        console.log(error);
      }
    },
  });

  /***********Styled component */
  const LoginContainer = styled(Box)(({ theme }) => ({
    display: "flex",
    flex: "1 1 auto",
    height: "100%",
    width: "100%",

    [theme.breakpoints.up("xs")]: {
      flexDirection: "column-reverse",
    },
    [theme.breakpoints.up("md")]: {
      flexDirection: "row",
    },
  }));

  const RightBox = styled(Box)(({ theme }) => ({
    backgroundColor: "rgb(14, 8, 39)",
    display: "flex",
    flexDirection: "column",
    maxWidth: "100%",

    [theme.breakpoints.up("xs")]: {
      flex: "1 1 auto",
      padding: "32px",
    },
    [theme.breakpoints.up("md")]: {
      flex: "0 0 auto",
      justifyContent: "center",
      padding: "64px",
      width: "600px",
    },
  }));

  const LeftBox = styled(Box)(({ theme }) => ({
    display: "flex",
    alignItems: "center",
    backgroundColor: "rgb(28, 37, 54)",
    backgroundImage: "url(/assets/gradient-bg.svg)",
    backgroundPosition: "center top",
    backgroundRepeat: "no-repeat",
    color: "rgb(255, 255, 255)",
    justifyContent: "center",

    [theme.breakpoints.up("xs")]: {
      flex: "0 0 auto",
      padding: "32px",
    },
    [theme.breakpoints.up("md")]: {
      flex: "1 1 auto",
      padding: "64px",
    },
  }));

  return (
    <LoginContainer>
      <LeftBox>
        <Box sx={{ maxWidth: "900px" }}>
          <Typography variant="h4"> Welcome to Backtic</Typography>
          <Typography sx={{ color: "rgb(108, 115, 127)" }}>
            Some cool text here to represent out Backtick
          </Typography>
        </Box>
      </LeftBox>
      <RightBox>
        <div>
          <Box mb={"32px"}>
            <Link to="/">
              <img src={Logo} alt="Backtick Logo" width={140} />
            </Link>
          </Box>
        </div>
        <div>
          <Stack direction="column" mb={"32px"}>
            <Typography variant="h4" sx={{ color: "rgb(108, 115, 127)" }}>
              Login
            </Typography>
            <Typography sx={{ color: "rgb(108, 115, 127)" }}>
              Don't have an account? <Link to="/register">Register</Link>
            </Typography>
          </Stack>

          <form onSubmit={formik.handleSubmit}>
            <Stack direction="column">
              <TextField
                fullWidth
                id="email"
                name="email"
                label="Email"
                value={formik.values.email}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={formik.touched.email && Boolean(formik.errors.email)}
                helperText={formik.touched.email && formik.errors.email}
              />
              <TextField
                fullWidth
                id="password"
                name="password"
                label="Password"
                type="password"
                value={formik.values.password}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={
                  formik.touched.password && Boolean(formik.errors.password)
                }
                helperText={formik.touched.password && formik.errors.password}
                sx={{ marginTop: "24px" }}
              />
            </Stack>
            <Button
              color="primary"
              variant="contained"
              fullWidth
              type="submit"
              size="large"
              sx={{ marginTop: "24px" }}
            >
              Submit
            </Button>
          </form>
        </div>
      </RightBox>
    </LoginContainer>
  );
};

export default Login;
英文:

Tyring to play with react

Created a login page to have email and password as input field using MUI, formik and yup
But whenever I try to enter any text after one character the input loses the focus. Everything else works as expected.

If I move those code to app.js then there is no issue , but moving it back to login.jsx seems to not work at all.

below is my code

app.js

import {
Navigate,
RouterProvider,
createBrowserRouter,
} from &quot;react-router-dom&quot;;
import { ColorModeContext, useMode } from &quot;./theme&quot;;
import Login from &quot;./pages/login/Login&quot;;
import { useContext, useState } from &quot;react&quot;;
import { AuthContext } from &quot;./context/AuthContext&quot;;
import { Box, CssBaseline, ThemeProvider } from &quot;@mui/material&quot;;
import Home from &quot;./pages/home/Home&quot;;
import ErrorPage from &quot;./pages/error/Error&quot;;
import SidebarComponent from &quot;./components/sidebar/Sidebar&quot;;
import Register from &quot;./pages/register/Register&quot;;
function App() {
const currentUser = useContext(AuthContext);
const [theme, colorMode] = useMode();
const Layout = () =&gt; {
&lt;Box
sx={{
display: &quot;flex&quot;,
height: &quot;100%&quot;,
minHeight: &quot;400px&quot;,
}}
&gt;
&lt;SidebarComponent /&gt;
&lt;main&gt;rtest&lt;/main&gt;
&lt;/Box&gt;;
};
const ProtectedRoute = ({ children }) =&gt; {
if (!currentUser.user) {
return &lt;Navigate to=&quot;/login&quot; /&gt;;
}
return children;
};
const router = createBrowserRouter([
{
path: &quot;/&quot;,
element: (
&lt;ProtectedRoute&gt;
&lt;Layout /&gt;
&lt;/ProtectedRoute&gt;
),
children: [
{
path: &quot;/&quot;,
element: &lt;Home /&gt;,
},
],
errorElement: &lt;ErrorPage /&gt;,
},
{
path: &quot;/login&quot;,
element: &lt;Login /&gt;,
},
{
path: &quot;/login&quot;,
element: &lt;Register /&gt;,
},
]);
return (
&lt;ColorModeContext.Provider value={colorMode}&gt;
&lt;ThemeProvider theme={theme}&gt;
&lt;CssBaseline /&gt;
&lt;div className=&quot;App&quot;&gt;
&lt;RouterProvider router={router} /&gt;
&lt;/div&gt;
&lt;/ThemeProvider&gt;
&lt;/ColorModeContext.Provider&gt;
);
}
export default App;

Login.jsx

import Logo from &quot;../../assets/backticklogo.svg&quot;;
import { Link, useNavigate } from &quot;react-router-dom&quot;;
import { useContext, useEffect, useState } from &quot;react&quot;;
import { AuthContext } from &quot;../../context/AuthContext&quot;;
import apiClient from &quot;../../services/api&quot;;
import { Box, Button, Stack, TextField, Typography } from &quot;@mui/material&quot;;
import styled from &quot;@emotion/styled&quot;;
import { useFormik } from &quot;formik&quot;;
import * as yup from &quot;yup&quot;;
const validationSchema = yup.object({
email: yup
.string(&quot;Enter your email&quot;)
.email(&quot;Enter a valid email&quot;)
.required(&quot;Email is required&quot;),
password: yup
.string(&quot;Enter your password&quot;)
.min(8, &quot;Password should be of minimum 8 characters length&quot;)
.required(&quot;Password is required&quot;),
});
const Login = () =&gt; {
const localplainTextToken = localStorage.getItem(&quot;plainTextToken&quot;) || null;
const [isAuth, setIsAuth] = useState(localStorage.getItem(&quot;isAuth&quot;) || null);
const [plainTextToken, setplainTextToken] = useState(localplainTextToken);
const remember = true;
const navigate = useNavigate();
const { user, dispatch } = useContext(AuthContext);
useEffect(() =&gt; {
isAuth &amp;&amp; navigate(&quot;/&quot;);
}, [isAuth]);
const handleUpdateUser = (userInfo) =&gt; {
console.log(userInfo);
dispatch({ type: &quot;LOGIN&quot;, payload: userInfo });
localStorage.setItem(&quot;user&quot;, JSON.stringify(userInfo));
localStorage.setItem(&quot;isAuth&quot;, true);
setIsAuth(true);
};
const formik = useFormik({
initialValues: {
email: &quot;&quot;,
password: &quot;&quot;,
},
validationSchema: validationSchema,
onSubmit: async (values) =&gt; {
// alert(JSON.stringify(values, null, 2));
try {
await apiClient
.post(&quot;login&quot;, {
email: values.email,
password: values.password,
})
.then((res) =&gt; {
console.log(res);
localStorage.setItem(&quot;plainTextToken&quot;, res.data.plainTextToken);
setplainTextToken(res.data.plainTextToken);
return res.data;
})
.then(async (data) =&gt; {
try {
let user = await apiClient.get(`user/${data.user_id}`, {
headers: {
Authorization: `Bearer ${data.plainTextToken}`,
Accept: &quot;application/json&quot;,
},
});
console.log(user);
handleUpdateUser(user.data);
// navigate(&quot;/&quot;);
} catch (error) {}
});
} catch (error) {
console.log(error);
}
},
});
/***********Styled component */
const LoginContainer = styled(Box)(({ theme }) =&gt; ({
display: &quot;flex&quot;,
flex: &quot;1 1 auto&quot;,
height: &quot;100%&quot;,
width: &quot;100%&quot;,
[theme.breakpoints.up(&quot;xs&quot;)]: {
flexDirection: &quot;column-reverse&quot;,
},
[theme.breakpoints.up(&quot;md&quot;)]: {
flexDirection: &quot;row&quot;,
},
}));
const RightBox = styled(Box)(({ theme }) =&gt; ({
backgroundColor: &quot;rgb(14, 8, 39)&quot;,
display: &quot;flex&quot;,
flexDirection: &quot;column&quot;,
maxWidth: &quot;100%&quot;,
[theme.breakpoints.up(&quot;xs&quot;)]: {
flex: &quot;1 1 auto&quot;,
padding: &quot;32px&quot;,
},
[theme.breakpoints.up(&quot;md&quot;)]: {
flex: &quot;0 0 auto&quot;,
justifyContent: &quot;center&quot;,
padding: &quot;64px&quot;,
width: &quot;600px&quot;,
},
}));
const LeftBox = styled(Box)(({ theme }) =&gt; ({
display: &quot;flex&quot;,
alignItems: &quot;center&quot;,
backgroundColor: &quot;rgb(28, 37, 54)&quot;,
backgroundImage: &quot;url(/assets/gradient-bg.svg)&quot;,
backgroundPosition: &quot;center top&quot;,
backgroundRepeat: &quot;no-repeat&quot;,
color: &quot;rgb(255, 255, 255)&quot;,
justifyContent: &quot;center&quot;,
[theme.breakpoints.up(&quot;xs&quot;)]: {
flex: &quot;0 0 auto&quot;,
padding: &quot;32px&quot;,
},
[theme.breakpoints.up(&quot;md&quot;)]: {
flex: &quot;1 1 auto&quot;,
padding: &quot;64px&quot;,
},
}));
return (
&lt;LoginContainer&gt;
&lt;LeftBox&gt;
&lt;Box sx={{ maxWidth: &quot;900px&quot; }}&gt;
&lt;Typography variant=&quot;h4&quot;&gt; Welcome to Backtic&lt;/Typography&gt;
&lt;Typography sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
Some cool text here to represent out Backtick
&lt;/Typography&gt;
&lt;/Box&gt;
&lt;/LeftBox&gt;
&lt;RightBox&gt;
&lt;div&gt;
&lt;Box mb={&quot;32px&quot;}&gt;
&lt;Link to=&quot;/&quot;&gt;
&lt;img src={Logo} alt=&quot;Backtick Logo&quot; width={140} /&gt;
&lt;/Link&gt;
&lt;/Box&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;Stack direction=&quot;column&quot; mb={&quot;32px&quot;}&gt;
&lt;Typography variant=&quot;h4&quot; sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
Login
&lt;/Typography&gt;
&lt;Typography sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
Don&#39;t have an account? &lt;Link to=&quot;/register&quot;&gt;Register&lt;/Link&gt;
&lt;/Typography&gt;
&lt;/Stack&gt;
&lt;form onSubmit={formik.handleSubmit}&gt;
&lt;Stack direction=&quot;column&quot;&gt;
&lt;TextField
fullWidth
id=&quot;email&quot;
name=&quot;email&quot;
label=&quot;Email&quot;
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.email &amp;&amp; Boolean(formik.errors.email)}
helperText={formik.touched.email &amp;&amp; formik.errors.email}
/&gt;
&lt;TextField
fullWidth
id=&quot;password&quot;
name=&quot;password&quot;
label=&quot;Password&quot;
type=&quot;password&quot;
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={
formik.touched.password &amp;&amp; Boolean(formik.errors.password)
}
helperText={formik.touched.password &amp;&amp; formik.errors.password}
sx={{ marginTop: &quot;24px&quot; }}
/&gt;
&lt;/Stack&gt;
&lt;Button
color=&quot;primary&quot;
variant=&quot;contained&quot;
fullWidth
type=&quot;submit&quot;
size=&quot;large&quot;
sx={{ marginTop: &quot;24px&quot; }}
&gt;
Submit
&lt;/Button&gt;
&lt;/form&gt;
&lt;/div&gt;
&lt;/RightBox&gt;
&lt;/LoginContainer&gt;
);
};
export default Login;

答案1

得分: 0

问题在于你在其他React组件内部声明了React组件。每次Login重新渲染时,因为状态更新,样式化组件会被重新声明。这会导致旧的“实例”及其整个子React树被卸载,新的“实例”和子React树被挂载。正是在输入框被卸载/挂载时导致它们失去焦点。

将多余的组件声明移出Login组件。

/***********Styled component */
const LoginContainer = styled(Box)(({ theme }) => ({
  display: "flex",
  flex: "1 1 auto",
  height: "100%",
  width: "100%",

  [theme.breakpoints.up("xs")]: {
    flexDirection: "column-reverse",
  },
  [theme.breakpoints.up("md")]: {
    flexDirection: "row",
  },
}));

const RightBox = styled(Box)(({ theme }) => ({
  backgroundColor: "rgb(14, 8, 39)",
  display: "flex",
  flexDirection: "column",
  maxWidth: "100%",

  [theme.breakpoints.up("xs")]: {
    flex: "1 1 auto",
    padding: "32px",
  },
  [theme.breakpoints.up("md")]: {
    flex: "0 0 auto",
    justifyContent: "center",
    padding: "64px",
    width: "600px",
  },
}));

const LeftBox = styled(Box)(({ theme }) => ({
  display: "flex",
  alignItems: "center",
  backgroundColor: "rgb(28, 37, 54)",
  backgroundImage: "url(/assets/gradient-bg.svg)",
  backgroundPosition: "center top",
  backgroundRepeat: "no-repeat",
  color: "rgb(255, 255, 255)",
  justifyContent: "center",

  [theme.breakpoints.up("xs")]: {
    flex: "0 0 auto",
    padding: "32px",
  },
  [theme.breakpoints.up("md")]: {
    flex: "1 1 auto",
    padding: "64px",
  },
}));
const Login = () => {
  ...

  return (
    <LoginContainer>
      <LeftBox>
        <Box sx={{ maxWidth: "900px" }}>
          <Typography variant="h4"> Welcome to Backtic</Typography>
          <Typography sx={{ color: "rgb(108, 115, 127)" }}>
            Some cool text here to represent out Backtick
          </Typography>
        </Box>
      </LeftBox>
      <RightBox>
        <div>
          <Box mb={"32px"}>
            <Link to="/">
              <img src={Logo} alt="Backtick Logo" width={140} />
            </Link>
          </Box>
        </div>
        <div>
          <Stack direction="column" mb={"32px"}>
            <Typography variant="h4" sx={{ color: "rgb(108, 115, 127)" }}>
              Login
            </Typography>
            <Typography sx={{ color: "rgb(108, 115, 127)" }}>
              Don't have an account? <Link to="/register">Register</Link>
            </Typography>
          </Stack>

          <form onSubmit={formik.handleSubmit}>
            <Stack direction="column">
              <TextField
                fullWidth
                id="email"
                name="email"
                label="Email"
                value={formik.values.email}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={formik.touched.email && Boolean(formik.errors.email)}
                helperText={formik.touched.email && formik.errors.email}
              />
              <TextField
                fullWidth
                id="password"
                name="password"
                label="Password"
                type="password"
                value={formik.values.password}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={
                  formik.touched.password && Boolean(formik.errors.password)
                }
                helperText={formik.touched.password && formik.errors.password}
                sx={{ marginTop: "24px" }}
              />
            </Stack>
            <Button
              color="primary"
              variant="contained"
              fullWidth
              type="submit"
              size="large"
              sx={{ marginTop: "24px" }}
            >
              Submit
            </Button>
          </form>
        </div>
      </RightBox>
    </LoginContainer>
  );
};

export default Login;

你可能还需要在App组件中对LayoutProtectedRoute做同样的操作。

英文:

The issue is that you are declaring React components inside other React components. Each time Login rerenders because the state is updated, the styled components are redeclared. This has the net effect of unmounting the old "instance" and its entire sub-ReactTree, and mounting the new "instance" and sub-ReactTree. It's when the inputs are unmouted/mounted that causes them to lose focus.

Move the extraneous component declarations out of the Login component.

/***********Styled component */
const LoginContainer = styled(Box)(({ theme }) =&gt; ({
  display: &quot;flex&quot;,
  flex: &quot;1 1 auto&quot;,
  height: &quot;100%&quot;,
  width: &quot;100%&quot;,

  [theme.breakpoints.up(&quot;xs&quot;)]: {
    flexDirection: &quot;column-reverse&quot;,
  },
  [theme.breakpoints.up(&quot;md&quot;)]: {
    flexDirection: &quot;row&quot;,
  },
}));

const RightBox = styled(Box)(({ theme }) =&gt; ({
  backgroundColor: &quot;rgb(14, 8, 39)&quot;,
  display: &quot;flex&quot;,
  flexDirection: &quot;column&quot;,
  maxWidth: &quot;100%&quot;,

  [theme.breakpoints.up(&quot;xs&quot;)]: {
    flex: &quot;1 1 auto&quot;,
    padding: &quot;32px&quot;,
  },
  [theme.breakpoints.up(&quot;md&quot;)]: {
    flex: &quot;0 0 auto&quot;,
    justifyContent: &quot;center&quot;,
    padding: &quot;64px&quot;,
    width: &quot;600px&quot;,
  },
}));

const LeftBox = styled(Box)(({ theme }) =&gt; ({
  display: &quot;flex&quot;,
  alignItems: &quot;center&quot;,
  backgroundColor: &quot;rgb(28, 37, 54)&quot;,
  backgroundImage: &quot;url(/assets/gradient-bg.svg)&quot;,
  backgroundPosition: &quot;center top&quot;,
  backgroundRepeat: &quot;no-repeat&quot;,
  color: &quot;rgb(255, 255, 255)&quot;,
  justifyContent: &quot;center&quot;,

  [theme.breakpoints.up(&quot;xs&quot;)]: {
    flex: &quot;0 0 auto&quot;,
    padding: &quot;32px&quot;,
  },
  [theme.breakpoints.up(&quot;md&quot;)]: {
    flex: &quot;1 1 auto&quot;,
    padding: &quot;64px&quot;,
  },
}));
const Login = () =&gt; {
  ...

  return (
    &lt;LoginContainer&gt;
      &lt;LeftBox&gt;
        &lt;Box sx={{ maxWidth: &quot;900px&quot; }}&gt;
          &lt;Typography variant=&quot;h4&quot;&gt; Welcome to Backtic&lt;/Typography&gt;
          &lt;Typography sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
            Some cool text here to represent out Backtick
          &lt;/Typography&gt;
        &lt;/Box&gt;
      &lt;/LeftBox&gt;
      &lt;RightBox&gt;
        &lt;div&gt;
          &lt;Box mb={&quot;32px&quot;}&gt;
            &lt;Link to=&quot;/&quot;&gt;
              &lt;img src={Logo} alt=&quot;Backtick Logo&quot; width={140} /&gt;
            &lt;/Link&gt;
          &lt;/Box&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;Stack direction=&quot;column&quot; mb={&quot;32px&quot;}&gt;
            &lt;Typography variant=&quot;h4&quot; sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
              Login
            &lt;/Typography&gt;
            &lt;Typography sx={{ color: &quot;rgb(108, 115, 127)&quot; }}&gt;
              Don&#39;t have an account? &lt;Link to=&quot;/register&quot;&gt;Register&lt;/Link&gt;
            &lt;/Typography&gt;
          &lt;/Stack&gt;

          &lt;form onSubmit={formik.handleSubmit}&gt;
            &lt;Stack direction=&quot;column&quot;&gt;
              &lt;TextField
                fullWidth
                id=&quot;email&quot;
                name=&quot;email&quot;
                label=&quot;Email&quot;
                value={formik.values.email}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={formik.touched.email &amp;&amp; Boolean(formik.errors.email)}
                helperText={formik.touched.email &amp;&amp; formik.errors.email}
              /&gt;
              &lt;TextField
                fullWidth
                id=&quot;password&quot;
                name=&quot;password&quot;
                label=&quot;Password&quot;
                type=&quot;password&quot;
                value={formik.values.password}
                onChange={formik.handleChange}
                onBlur={formik.handleBlur}
                error={
                  formik.touched.password &amp;&amp; Boolean(formik.errors.password)
                }
                helperText={formik.touched.password &amp;&amp; formik.errors.password}
                sx={{ marginTop: &quot;24px&quot; }}
              /&gt;
            &lt;/Stack&gt;
            &lt;Button
              color=&quot;primary&quot;
              variant=&quot;contained&quot;
              fullWidth
              type=&quot;submit&quot;
              size=&quot;large&quot;
              sx={{ marginTop: &quot;24px&quot; }}
            &gt;
              Submit
            &lt;/Button&gt;
          &lt;/form&gt;
        &lt;/div&gt;
      &lt;/RightBox&gt;
    &lt;/LoginContainer&gt;
  );
};

export default Login;

You will likely want to also do the same for Layout and ProtectedRoute in the App component.

huangapple
  • 本文由 发表于 2023年7月27日 15:16:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/76777301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定