reactjs 使用frebase和redux在_app.js中进行访问限制

qvsjd97n  于 2023-05-22  发布在  React
关注(0)|答案(2)|浏览(144)

我有一个应用程序,人们可以访问网站,如果不登录,但他们应该能够访问"/app""/app/*"只有在经过验证。我下面的代码可以工作,但由于某种原因,在显示消息"you're not allowed to..."之前显示了"/app"的内容的半秒或一秒。你知道为什么吗?

import { Provider, useDispatch, useSelector } from 'react-redux';
import { useRouter } from 'next/router';
import '../styles/front.css';
import '../styles/app.css';
import React, { useEffect, useState } from 'react';
import { wrapper, store } from '../store';
import { login, logout, selectUser } from "../redux/slices/userSlice";
import { auth } from '../firebase';

function MyApp({ Component, pageProps }) {
  const user = useSelector(selectUser);
  const dispatch = useDispatch();
  const router = useRouter();
  const isAppPage = router.pathname.startsWith('/app');
  const [shouldRender, setShouldRender] = useState(true); // New state variable
  const [loading, setLoading] = useState(true);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((userAuth) => {
      if (userAuth) {
        dispatch(login({
          email: userAuth.email,
          uid: userAuth.uid,
          displayName: userAuth.displayName,
          photoUrl: userAuth.photoURL
        }));
        setIsAuthenticated(true);
      } else {
        if (isAppPage) {
          setShouldRender(false);
        }
        dispatch(logout());
        setIsAuthenticated(false);
      }
      setLoading(false); // Set loading to false once the authentication status is checked
    });

    return () => unsubscribe(); // Cleanup the event listener when the component unmounts
  }, []);

  return (
    <Provider store={store}>
      {shouldRender ? <Component {...pageProps} /> : <p>You're not allowed to access that page.</p>}
    </Provider>
  );
}

export default wrapper.withRedux(MyApp);
gr8qqesn

gr8qqesn1#

基本上,您需要一个具有第三个值的条件,该条件既不是“显示内容”,也不是“您看不到此内容”。类似于“挂起”状态,它有条件地既不呈现Component文本,也不呈现"You're not allowed to access that page."文本。
初始的shouldRender状态与您不想立即呈现的这两个状态之一相匹配。从undefined开始,显式检查是否存在,并有条件地返回null或加载指示符等。示例:

function MyApp({ Component, pageProps }) {
  const user = useSelector(selectUser);
  const dispatch = useDispatch();
  const router = useRouter();
  const isAppPage = router.pathname.startsWith('/app');

  const [shouldRender, setShouldRender] = useState(); // initially undefined

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

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((userAuth) => {
      if (userAuth) {
        dispatch(login({
          email: userAuth.email,
          uid: userAuth.uid,
          displayName: userAuth.displayName,
          photoUrl: userAuth.photoURL
        }));
        setIsAuthenticated(true);
        setShouldRender(true); // <-- show the content
      } else {
        if (isAppPage) {
          setShouldRender(false); // <-- hide content
        }
        dispatch(logout());
        setIsAuthenticated(false);
      }
      setLoading(false);
    });

    return () => unsubscribe();
  }, []);

  if (shouldRender === undefined) {
    return null; // or loading indicator/spinner/etc
  }

  return (
    <Provider store={store}>
      {shouldRender
        ? <Component {...pageProps} />
        : <p>You're not allowed to access that page.</p>
      }
    </Provider>
  );
}
gajydyqb

gajydyqb2#

这是因为shouldRender在第一次加载时为true,之后它进入useEffect并在onAuthStateChanged中获取auth状态。
你应该在这里设置为false:

const [shouldRender, setShouldRender] = useState(false); // New state variable

并在其中更新:

if (userAuth) {
    dispatch(login({
      email: userAuth.email,
      uid: userAuth.uid,
      displayName: userAuth.displayName,
      photoUrl: userAuth.photoURL
    }));
    setShouldRender(true);
    setIsAuthenticated(true);
  }

更新:可以使用其他状态检查加载状态。所以用途:

const [loaded, setLoaded] = useState(false);    
const [shouldRender, setShouldRender] = useState(false);

并在useEffect内部更新:

if (userAuth) {
    dispatch(login({
      email: userAuth.email,
      uid: userAuth.uid,
      displayName: userAuth.displayName,
      photoUrl: userAuth.photoURL
    }));
    setLoaded(true);
    setShouldRender(true);
    setIsAuthenticated(true);
  }

对于渲染,请使用以下命令:

return (
    <Provider store={store}>
      {!loaded? <LoaderComponent />: shouldRender
        ? <Component {...pageProps} />
        : <p>You're not allowed to access that page.</p>
      }
    </Provider>
  );

相关问题