ReactJS 中的私有路由条件运算符

Private Route Conditional Operator in ReactJS

似乎是个小问题。

我有一个应用程序,人们可以在其中通过“条纹”进行订阅。想根据订阅授予对几个 URL 的访问权限,否则将它们带回“个人资料”页面。

有些东西不工作。

  1. 获取 订阅 的 Firebase 查询未给出订阅结果。不知何故 onSnapShot 没有获取任何东西。可能是因为在页面渲染开始时 UID 为 null。

  2. 打开的条件运算符无效。不确定这个问题是什么。



function PaidRoutes(props) {


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

  useEffect(() => {
    const unsub = auth.onAuthStateChanged((authObject) => {
      unsub();
      if (authObject) {
        setLoading(true);
        const uid = auth.currentUser?.uid;
        console.log('UID ==>', uid);
        let docRef = query(collection(db, 'customers', uid, 'subscription'));
        console.log('DOC REF ==> ', docRef);
        onSnapshot(docRef, (snap) => {
          snap.forEach((doc) => {
            console.log('Role of Subscription', doc.data().role);
            setSubscription(doc.data().role);
          });
        });
      } else {
        console.log('not logged in');
        setLoading(false);
      }
    });
    return () => {
      unsub();
    };
  }, []);



  return (
    <Route
      {...props}
      render={(props) =>
        subscription ? (
          <Component {...props} />
        ) : (
          <Redirect to='/profileScreen' />
        )
      }
    />
  );

感谢德鲁的评论。 react-router-dom安装的版本是5.2.0

问题

我在 PaidRoute 代码中看到的潜在问题:

  1. 在身份验证状态处理程序中调用取消订阅函数,这可能允许身份验证检查在初始身份验证更改时工作一次,但随后将自行取消订阅并停止工作,直到组件重新安装。
  2. loading 状态最初是 false,因此在初始渲染时基于它的任何检查都不会执行您想要的操作。 loading 也不用于推迟条件渲染。
  3. subscription 状态最初是一个空数组,它仍然是真实的,因此无论任何身份验证状态如何,检查它的条件逻辑都可能允许访问受保护的路由。

解决方案

  1. 不要取消订阅回调中的身份验证更改侦听器。
  2. loading 开始处理初始渲染周期。有条件地呈现 null 或一些加载指示器。
  3. 从空 subscription 状态开始。

代码:

function PaidRoutes(props) {
  const [subscription, setSubscription] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((authObject) => {
      if (authObject) {
        setLoading(true);
        const uid = auth.currentUser?.uid;
        console.log('UID ==>', uid);
        const docRef = query(collection(db, 'customers', uid, 'subscription'));
        console.log('DOC REF ==> ', docRef);
        onSnapshot(docRef, (snap) => {
          snap.forEach((doc) => {
            console.log('Role of Subscription', doc.data().role);
            setSubscription(doc.data().role);
          });
        });
      } else {
        console.log('not logged in');
        setSubscription(null); // <-- reset auth state
      }
      setLoading(false); // <-- clear loading state outside if-else
    });

    return unsubscribe;
  }, []);

  if (loading) {
    return null; // or loading indicator, spinner, etc...
  }

  return subscription ? (
    <Route {...props} />
  ) : (
    <Redirect to='/profileScreen' />
  );
}