首页 > 解决方案 > history.push() 不能在 firebase 的身份验证中使用 react

问题描述

我正在使用 react、firebase auth 和 context api 构建身份验证。

登录.js

import React, { useEffect, useState } from 'react';
import { Form, Button, Container, Card } from 'react-bootstrap';
import { useAuth } from '../contextApi/contextApi';
import { Link } from 'react-router-dom';
import { useHistory } from 'react-router-dom';

function SignIn() {
  let history = useHistory();
  const { signIn } = useAuth();

  const emailRef = React.useRef(null);
  const passwordRef = React.useRef(null);

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

  let handleSubmit = async (e) => {
    e.preventDefault();
    console.log('connected');

    try {
      setLoading(true);
      await signIn(emailRef.current.value, passwordRef.current.value);
      console.log('push');
      history.push('/dashboard');
    } catch {
      alert('handleSubmit went wrong!');
    }
    history.push('/dashboard');
    setLoading(false);
  };

  return (
    <div style={{ backgroundColor: '#a9a9a9' }}>
      <Container
        className="signin d-flex align-items-center justify-content-center"
        style={{
          minHeight: '100vh',
        }}
      >
        <Card className="shadow">
          <Card.Body>
            <h2 className="text-center mb-4">Sign In</h2>
            <Form onSubmit={handleSubmit}>
              <Form.Group controlId="formBasicEmail">
                <Form.Label>Email address</Form.Label>
                <Form.Control
                  type="email"
                  placeholder="Enter email"
                  ref={emailRef}
                  required
                />
                <Form.Text className="text-muted">
                  We'll never share your email with anyone else.
                </Form.Text>
              </Form.Group>

              <Form.Group controlId="formBasicPassword">
                <Form.Label>Password</Form.Label>
                <Form.Control
                  type="password"
                  placeholder="Password"
                  ref={passwordRef}
                  required
                />
              </Form.Group>
              <Button variant="primary" type="submit" disabled={loading}>
                Submit
              </Button>
            </Form>
            <div className="w-100 text-center mt-2">
              Need an account? <Link to="/signup">Sign up</Link>
            </div>
            <div className="w-100 text-center mt-2">
              Forgot password? <Link to="/forgotpassword">Click here</Link>
            </div>
            <div className="w-100 text-center mt-2">
              Back to <Link to="/">Home page</Link>
            </div>
          </Card.Body>
        </Card>
      </Container>
    </div>
  );
}

export default SignIn;

每当我成功登录时一切正常,但如果我稍后登录失败,即使我输入了正确的密码/电子邮件,登录页面也不会重定向到仪表板页面。

可以对我的代码的哪一部分错误进行一些说明吗?

contextApi.js


import React, { useContext, useEffect, useState } from 'react';
import { auth } from '../firebase';
import { useHistory } from 'react-router-dom';

const ContextApi = React.createContext();

export function useAuth() {
  return useContext(ContextApi);
}

export const ContextApiProvider = ({ children }) => {
  let [currentUser, setCurrentUser] = useState();
  let [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribed = auth.onAuthStateChanged((user) => {
      if (user) {
        setCurrentUser(user);
        setLoading(false);
      } else {
        setCurrentUser(null);
        setLoading(false);
        console.log(currentUser);
      }
    });
    return unsubscribed;
  }, []);

  const signIn = (email, password) => {
    auth.signInWithEmailAndPassword(email, password).catch(function (error) {
      // Handle Errors here.
      console.log(error);

      let errorCode = error.code;
      let errorMessage = error.message;
      if (errorCode === 'auth/wrong-password') {
        alert('sign in failed! Wrong password.');
      } else if (!errorMessage) {
        alert('you are signed in!');
      } else {
        alert(`sign in failed! ${errorMessage}`);
      }
    });
  };

  const signUp = (email, password) => {
    auth.createUserWithEmailAndPassword(email, password).catch((error) => {
      let errorCode = error.code;
      let errorMessage = error.message;
      console.log(errorMessage);
      console.log(error);
      console.log(errorCode);
      if (errorCode === 'auth/weak-password') {
        alert(`signup failed! The password is too weak!`);
      } else if (!errorMessage) {
        alert('signed up successfully');
      } else {
        alert(`sign up failed! ${errorMessage}`);
      }
    });
  };

  const resetPassword = (email) => {
    auth.sendPasswordResetEmail(email).catch((error) => {
      let errorCode = error.code;
      let errorMessage = error.message;
      if (errorCode === 'auth/invalid-email') {
        alert('email not found');
      } else {
        alert(errorMessage);
      }
    });
  };

  const logout = () => {
    return auth.signOut();
  };

  let value = {
    signIn,
    currentUser,
    signUp,
    resetPassword,
    logout,
  };

  return (
    <ContextApi.Provider value={value}>
      {!loading && children}
      {/* {children} */}
    </ContextApi.Provider>
  );
};

标签: javascriptreactjsfirebasefirebase-authentication

解决方案


您没有正确使用 firebase 功能,这里是您应该如何使用它的示例(来自文档)

const signIn = (email, password) => { 
  firebase.auth().signInWithEmailAndPassword(email, password)
 .then((user) => {
  // Signed in 
  //here you call history push (or a callback defined somone else)
  // doc state that here we know that credentials was accepted
  // while await means simply that the async code ended
  // Then is better since you aren't blocking anything and it is more clean (most importantly people who maintain your code will have no issue)
  // you will have no issue if firebase update something in thier lib ...
  // history need to be defined before or passed as param
  history.push('/dashboard')
  // ...
  })
 .catch((error) => {
   // nothing is required from you here (but you can for example show "forget password link)
  var errorCode = error.code;
    var errorMessage = error.message;
  });
 }

虽然 await 应该可以工作,但您无法确定用户是否已登录,上面的代码是另一种处理方式。


推荐阅读