反应 Firebase 私人路线

时间:2020-12-20 13:01:49

标签: reactjs redux firebase-authentication

需要帮助使用 react reduxfirebase
制作私有路由 问题是:

当我点击登录时,用户正确签名并且状态在 redux 商店中更新,但用户没有被重定向到仪表板,但在单击按钮登录后输入“/dashboard”URL 有效,也尝试去“ /dashboard" 当用户状态 user null 工作时

App.js

import React, { useEffect } from "react";
import { connect, Provider } from "react-redux";
import store from "./store";
import { setUser, clearUser } from "./actions/userActions";
import {
  BrowserRouter as Router,
  Route,
  Switch,
  withRouter,
} from "react-router-dom";
import Login from "./components/auth/Login";
import Register from "./components/auth/Register";
import Home from "./components/pages/Home";
import Dashboard from "./components/pages/Dashboard";

import firebase from "./firebase";

import PrivateRoute from "./components/PrivateRoute";

function App({ setUser, clearUser, currentUser, history, isLoading }) {
  useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        setUser(user);
      } else {
        clearUser();
      }
    });

    return () => {
      unsubscribe();
      clearUser();
    };
  }, [clearUser, history, setUser]);

  return (
    <Switch>
      <Route path="/" component={Home} exact />
      <PrivateRoute
        path="/dashboard"
        component={Dashboard}
        currentUser={currentUser}
        isLoading={isLoading}
      />
      <Route path="/login" component={Login} />
      <Route path="/register" component={Register} />
    </Switch>
  );
}

const mapStateToProps = (state) => ({
  isLoading: state.user.isLoading,
  currentUser: state.user.currentUser,
});

const AppWithRouter = withRouter(
  connect(mapStateToProps, { setUser, clearUser })(App)
);

const AppWithAuth = () => (
  <Provider store={store}>
    <Router>
      <AppWithRouter />
    </Router>
  </Provider>
);

export default AppWithAuth;

PrivateRoute.js

import React from "react";

import { Redirect, Route } from "react-router-dom";

const PrivateRoute = ({
  component: Component,
  currentUser,
  isLoading,
  ...rest
}) => {
  return isLoading ? (
    <h1>Spinner</h1>
  ) : (
    <Route
      {...rest}
      render={(props) =>
        currentUser ? <Component {...props} /> : <Redirect to="login" />
      }
    />
  );
};

export default PrivateRoute;

Login.js

import React, { useState } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
//firebase
import firebase from "../../firebase";

import {
  Grid,
  Box,
  TextField,
  CssBaseline,
  Avatar,
  Container,
  Typography,
  LinearProgress,
  Button,
  makeStyles,
} from "@material-ui/core";

const Login = (props) => {
  const [form, setForm] = useState({
    email: "",
    password: "",
  });

  const [errors, setErrors] = useState([]);

  const [loading, setLoading] = useState(false);

  const handleChange = (event) =>
    setForm({ ...form, [event.target.name]: event.target.value });

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!form.email || !form.password) {
      return setErrors(["Fill in all fields"]);
    }

    setErrors([]);
    setLoading(true);

    firebase
      .auth()
      .signInWithEmailAndPassword(form.email, form.password)
      .then((signedInUser) => {
        setLoading(false);
        props.history.push("dashboard");
      })
      .catch((err) => {
        setLoading(false);
        setErrors([err.message]);
      });
  };

  const useStyles = makeStyles((theme) => ({
    paper: {
      marginTop: theme.spacing(8),
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
    },
    avatar: {
      margin: theme.spacing(1),
      backgroundColor: theme.palette.secondary.main,
    },
    form: {
      width: "100%", // Fix IE 11 issue.
      marginTop: theme.spacing(1),
    },
    submit: {
      margin: theme.spacing(3, 0, 2),
    },
  }));

  const classes = useStyles();

  return (
    <Container component="main" maxWidth="xs">
      <CssBaseline />
      <div className={classes.paper}>
        <Avatar className={classes.avatar}></Avatar>
        <Typography component="h1" variant="h5">
          Sign in
        </Typography>
        <form className={classes.form} noValidate onsubmit={handleSubmit}>
          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            id="email"
            label="Email Address"
            name="email"
            autoComplete="email"
            onChange={handleChange}
          />
          <TextField
            variant="outlined"
            margin="normal"
            required
            fullWidth
            name="password"
            label="Password"
            type="password"
            id="password"
            autoComplete="current-password"
            onChange={handleChange}
          />

          <Box color="red">
            {errors.length > 0 && errors.map((err, i) => <span>{err}</span>)}
          </Box>
          <Grid justify="center"></Grid>

          {loading ? <LinearProgress size={14} /> : ""}
          <Button
            type="submit"
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
            onClick={handleSubmit}
          >
            Sign in
          </Button>
          <Grid container>
            <Grid item>
              <Link to="/register" variant="body2">
                {"Don't have an account? Sign Up"}
              </Link>
            </Grid>
          </Grid>
        </form>
      </div>
      <Box mt={8}></Box>
    </Container>
  );
};

const mapStateToProps = (state) => ({
  isLoading: state.user.isLoading,
  currentUser: state.user.currentUser,
});

export default connect(mapStateToProps)(Login);

0 个答案:

没有答案