玩弄反作用力

创建了一个登录页面,使用MUI、Formik和YUP将邮箱和密码作为输入字段 但是,每当我try 在一个字符之后输入任何文本时,输入都会失go 焦点.其他一切都像预期的那样运行.

如果我将这些代码移到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;

登录.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;

推荐答案

问题是您在其他Reaction组件中声明了Reaction组件.每次由于状态更新而重新呈现Login次时,都会重新声明已设置样式的组件.这样做的最终效果是卸载旧的"实例"及其整个子ReactTree,并挂载新的"实例"和子ReactTree.只有当输入被取消插入/挂载时,它们才会失go 焦点.

将无关的组件声明移出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执行相同的操作.

Reactjs相关问答推荐

Inbox Enum类型以React组件状态时出现TypScript错误

使用Overpass API Endpoint计算 map 上的面积

从Microsoft Excel粘贴复制的单元格时,将Excel单元格格式(粗体、下划线、斜体)带入Reaction

Reactjs中的chartjs和reaction-chartjs-2的问题

React,React Router,Joy UI:如何在导航离开和返回后禁用snackbar重新出现?

如何访问子集合中的文档?

生成Reaction Vite应用程序的停靠容器时无法识别环境变量

无法在REACTION TANSTACK查询中传递参数

透明MOV文件未出现在我的React网页中

MUI 日期 Select 器 - 最小日期混乱

如何在我的 React 应用程序中仅显示我的 Register 组件

onClick 事件处理程序未应用于样式组件

更新对象状态的父数组时记住子组件

如何测试根据 prop 更改 CSS 属性的 useEffect 钩子?

React Wordpress Apache 在索引之外重新加载 -> 未找到页面

redux 工具包使用中间件构建器函数时,必须返回一个中间件数组

React Router v6 路径中的符号

MUI - ButtonGroup fullWidth 条件屏幕大小不起作用?

React CSSTransition 两次创建新页面并在这两个相同的页面上运行转换

如何在 React 中的 Material Ui 多选中设置默认值?