Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
248 views
in Technique[技术] by (71.8m points)

javascript - react redux, firebas auth, on refresh useSelector show logged in page or re-direct away if no user

In the main app I have a useEffect hook which will check if user is logged in:

useEffect(() => {
    auth.onAuthStateChanged((user) => {
      if (user) {
        // User is signed in.
        dispatch(
          setUser({
            name: user.displayName,
            email: user.email,
          })
        );
      } else {
        // No user is signed in.
      }
    });
  }, [dispatch]);

This is calling an action from my user reducer setUser to store the user information. On refresh, or if say I went to the Dashboard page I'd like it to show the page if user is logged in or re-direct to home page if not.

For now I'm changing the window location to test, but I don't think this is the right way? As it won't be stored in Browser history would it? That's another problem anyway

At the moment on load, the user is null, so it is running the re-direct even if a user is logged in. How would I write it to wait until firebase has checked if the user exists first - am I going to have to use the auth state change directly in this component instead of using a selector? And the same for everywhere else in my app? I think I may have figured it out myself while writing this question. Would that be the best way? A custom hook perhaps that returns the user?

Below is the Dashboard page:

import Section from "../components/Section/Section";
import Container from "../components/Container/Container";
import { useSelector } from "react-redux";
import { userInfo } from "../store/slices/user";

const Dashboard = () => {
  const user = useSelector(userInfo);

  const html = user ? (
    <Section>
      <Container>
        <h1>Dashboard</h1>
        <p>If you can see this then you are logged in</p>
      </Container>
    </Section>
  ) : (
    (window.location.href = "/")
  );

  return html;
};

export default Dashboard;

Thanks

question from:https://stackoverflow.com/questions/65877673/react-redux-firebas-auth-on-refresh-useselector-show-logged-in-page-or-re-dire

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Login Pending State

I think that a selector is fine, but you need to have additional information in your store that tells you whether or not someone is currently logging in.

At some point in your app you are calling a sign-in method which is an async function that takes time to execute. I'm not sure if you are await-ing the result or not. Eventually the internal state of auth will change and the onAuthStateChanged callback from your useEffect will dispatch the user object to the store.

I propose an additional dispatch that sends some sort of PENDING_LOGIN action to your store at the very beginning of the login. Somewhere in your store you can save either a boolean isLoggingIn or an enum loginState.

You would change your login handler:

const handleLogin = async () => {
  // immediately dispatch the pending login
  dispatch({type: "PENDING_LOGIN" });
  const {user} = await await auth.signInAnonymously();
  // could dispatch `setUser` action from here instead of from `useEffect`, if you want to
}

In your Dashboard component, you can access this new information from your store.

const Dashboard = () => {
  const user = useSelector(userInfo);
  const isLoggingIn = useSelector(someSelector);

  if ( ! user && ! isLoggingIn ) {
    window.location.href = "/";
  }

  return (
    <Section>
      <Container>
        <h1>Dashboard</h1>
        {user 
           ? <p>If you can see this then you are logged in</p> 
           : <p>Logging in...</p>
        }
      </Container>
    </Section>
  )
};

window.location

Changing window.location does actually add the URL to history. Here's some info from MDN.

Regarding setting a string value to window.location:

Whenever a new value is assigned to the location object, a document will be loaded using the URL as if location.assign() had been called with the modified URL.

Regarding this assign() method:

The Location.assign() method causes the window to load and display the document at the URL specified. After the navigation occurs, the user can navigate back to the page that called Location.assign() by pressing the "back" button.

If you want to navigate to a page without adding it to history, there is a separate method for that.

The replace() method of the Location interface replaces the current resource with the one at the provided URL. The difference from the assign() method is that after using replace() the current page will not be saved in session History, meaning the user won't be able to use the back button to navigate to it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...