gpt4 book ai didi

javascript - 将仅客户端路由与来自 Contentful 的页面模板一起使用

转载 作者:行者123 更新时间:2023-12-04 11:39:03 25 4
gpt4 key购买 nike

目标
我希望对特定 URL ( /dashboard ) 下的内容使用仅限客户端的路由。其中一些内容将来自 Contentful 并使用页面模板。这条路线的一个例子是 {MYDOMAIN}/dashboard/{SLUG_FROM_CONTENTFUL} .这样做的目的是确保我在代理机构工作过的项目无法被抓取/访问,并且只有在登录后才对“雇主”可见。
我试过的
我的页面是通过 gatsby-node.js 生成的.添加身份验证/仅客户端路由的方式取自 this example .据我所知,现在它的基础已经设置好并且工作正常。但是私有(private)路由似乎只在以下情况下有效:
如果我登录并导航到 /dashboard

  • 我显示Profile.js

  • 如果我没有登录并转到 /dashboard
  • 我显示Login.js

  • 所以这一切似乎都很好。当我转到 /dashboard/url-from-contentful 时,问题就出现了并且我没有登录。我得到了页面而不是被发送到 /dashboard/login .

    exports.createPages = async ({graphql, actions}) => {
    const { createPage } = actions;

    const { data } = await graphql(`
    query {
    agency: allContentfulAgency {
    edges {
    node {
    slug
    }
    }
    }
    }
    `);
    data.agency.edges.forEach(({ node }) => {
    createPage({
    path: `dashboard/${node.slug}`,
    component: path.resolve("src/templates/agency-template.js"),
    context: {
    slug: node.slug,
    },
    });
    });
    }

    exports.onCreatePage = async ({ page, actions }) => {
    const { createPage } = actions;

    if(page.path.match(/^\/dashboard/)) {
    page.matchPath = "/dashboard/*";

    createPage(page);
    }
    };
    我的 auth.js已设置(用户名和密码是基本的,因为我仍然只在本地开发):
    export const isBrowser = () => typeof window !== "undefined";

    export const getUser = () =>
    isBrowser() && window.localStorage.getItem("gatsbyUser")
    ? JSON.parse(window.localStorage.getItem("gatsbyUser"))
    : {};

    const setUser = (user) =>
    window.localStorage.setItem("gatsbyUser", JSON.stringify(user));

    export const handleLogin = ({ username, password }) => {
    if (username === `john` && password === `pass`) {
    return setUser({
    username: `john`,
    name: `Johnny`,
    email: `johnny@example.org`,
    });
    }

    return false;
    };

    export const isLoggedIn = () => {
    const user = getUser();

    return !!user.username;
    };

    export const logout = (callback) => {
    setUser({});
    call
    };
    PrivateRoute.js设置如下:
    import React from "react";
    import { navigate } from "gatsby";
    import { isLoggedIn } from "../services/auth";

    const PrivateRoute = ({ component: Component, location, ...rest }) => {
    if (!isLoggedIn() && location.pathname !== `/dashboard/login`) {
    navigate("/dashboard/login");
    return null;
    }

    return <Component {...rest} />;
    };

    export default PrivateRoute;
    dashboard.js有以下内容。行 <PrivateRoute path="/dashboard/url-from-contentful" component={Agency} /> ,我在这里尝试了几件事 - 静态输入路线并使用 exact prop,使用路由参数,如 /:id , /:path , /:slug :

    import React from "react";
    import { Router } from "@reach/router";
    import Layout from "../components/Layout";
    import Profile from "../components/Profile";
    import Login from "../components/Login";
    import PrivateRoute from "../components/PrivateRoute";
    import Agency from "../templates/agency-template";

    const App = () => (
    <Layout>
    <Router>
    <PrivateRoute path="/dashboard/url-from-contentful" component={Agency} />
    <PrivateRoute path="/dashboard/profile" component={Profile} />
    <PrivateRoute path="/dashboard" />
    <Login path="/dashboard/login" />
    </Router>
    </Layout>
    );

    export default App;

    最后 agency-template.js

    import React from "react";
    import { graphql, Link } from "gatsby";
    import styled from "styled-components";
    import SEO from "../components/SEO";
    import Layout from "../components/Layout";
    import Gallery from "../components/Gallery";
    import GeneralContent from "../components/GeneralContent/GeneralContent";

    const agencyTemplate = ({ data }) => {
    const {
    name,
    excerpt,
    richDescription,
    richDescription: { raw },
    images,
    technology,
    website,
    } = data.agency;

    const [mainImage, ...projectImages] = images;

    return (
    <>
    <SEO title={name} description={excerpt} />
    <Layout>
    <div className="container__body">
    <GeneralContent title={name} />
    <Gallery mainImage={mainImage} />

    <GeneralContent title="Project Details" content={richDescription} />
    <div className="standard__images">
    <Gallery projectImages={projectImages} />
    </div>
    <ViewWebsite>
    <Link className="btn" to={website}>
    View the website
    </Link>
    </ViewWebsite>
    </div>
    </Layout>
    </>
    );
    };

    export const query = graphql`
    query ($slug: String!) {
    agency: contentfulAgency(slug: { eq: $slug }) {
    name
    excerpt
    technology
    website
    images {
    description
    gatsbyImageData(
    layout: FULL_WIDTH
    placeholder: TRACED_SVG
    formats: [AUTO, WEBP]
    quality: 90
    )
    }
    richDescription {
    raw
    }
    }
    }
    `;
    export default agencyTemplate;

    我认为 Gatsby 可以从 CMS 中选通内容,但考虑到它是 SSG,我可能错了。我可能误解了仅限客户端的基本原理。 React 中的概念和使用 Gatsby 对我来说仍然很新,所以任何帮助或指导实现目标将不胜感激。
    我最终做了什么
    所以我标记的答案是'让球滚动'的答案。解释状态发生的事情并要求 useContext或 redux 帮助我了解我哪里出错了。
    此外,使用 Web token 的建议促使我找到有关在应用程序中使用 Auth0 的更多信息。
    一旦我摆脱了使用 Gatsby 创建页面的心态(通过模板,通过 gatsby-node.s ),而是通过处理路由和 GraphQL 以“React 方式”(我知道 Gatsby 是用 React 构建的)来完成它变得更加清晰。除了身份验证之外,我最终所做的只是创建一个新的 <Agency />组件并将来自 GraphQL 的数据输入其中并使用我的 map() 更新路径.
    return (
    <>
    <Router>
    <DashboardArea path="/dashboard/" user={user} />
    {agencyData.map(({ node }, index) =>
    node.slug ? (
    <Agency key={index} data={node} path={`/dashboard/${node.slug}`} />
    ) : null
    )}
    </Router>
    </>
    );

    最佳答案

    我假设在您的 PrivateRoute 组件中,您错误地使用了 isLoggedIn 检查。从 auth.js 导入和使用 isLoggedIn 只会在最初运行,不会充当监听器。您可以做的是将 isLoggedin 的值存储在全局状态变量中,例如(useContext 或 redux),并制作一个自定义 Hook 来检查登录状态。其次避免直接访问localStorage,而是使用全局状态管理(useContext,redux)或本地状态管理(useState,this.state)。
    注意:当您通过直接在浏览器中粘贴 url 来访问路由时,它总是会刷新页面并且您存储的所有状态都会重新初始化。这可能是您遇到此问题的原因。浏览器不知道您之前已登录,因此它始终会在您的应用程序安装后进行验证。您可以做的是,您可以将 isLoggedIn 状态存储在浏览器的本地存储中。我个人喜欢为此使用 redux-persist。

    export const useGetUser = () => { //add use infront to make a custom hook
    return useSelector(state => state.gatsByUser) // access user info from redux store
    };


    export const handleLogin = ({ username, password }) => {
    //suggestion: don't validate password on client side or simply don't use password,
    //instead use tokens for validation on client side

    if (username === `john` && password === `pass`) {
    dispatch(setUserInfo({
    username: `john`,
    name: `Johnny`,
    email: `johnny@example.org`,
    isLoggedIn: true,
    }));
    return true;
    }

    return false;
    };


    // adding 'use' infront to make it a custom hook
    export const useIsLoggedIn = () => {
    //this will act as a listner when ever the state changes
    return useSelector(state => state.gatsByUser?.isLoggedIn ?? false);
    };

    export const logout = (callback) => {
    const dispatch = useDispatch(); // redux
    dispatch(clearUserInfo());
    };
    现在在私有(private)路线做
    import React from "react";
    import { navigate } from "gatsby";
    import { useIsLoggedIn } from "../services/auth";

    const PrivateRoute = ({ component: Component, location, ...rest }) => {
    const isLoggedIn = useIsLoggedIn();

    if (!isLoggedIn) {
    return navigate("/dashboard/login");
    }

    return <Component {...rest} />;
    };

    export default PrivateRoute;

    关于javascript - 将仅客户端路由与来自 Contentful 的页面模板一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68831676/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com