Bag*_*eye 5 javascript content-management-system reactjs gatsby
我希望对特定 URL ( /dashboard)下的内容使用仅客户端路由。其中一些内容将来自 Contentful 并使用页面模板。这条路线的一个例子是{MYDOMAIN}/dashboard/{SLUG_FROM_CONTENTFUL}。这样做的目的是确保我在代理机构工作过的项目无法被抓取/访问,并且只有“雇主”登录后才能看到。
我的页面是通过gatsby-node.js. 添加身份验证/仅客户端路由的方式取自此示例。现在它的基础已经设置好并且工作正常,据我所知。但私人路线似乎只在以下情况下有效:
如果我已登录并导航到 /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);
}
};
Run Code Online (Sandbox Code Playgroud)
我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
};
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
dashboard.js有以下内容。该行<PrivateRoute path="/dashboard/url-from-contentful" component={Agency} />,我在这里尝试了几件事 - 静态输入路线并使用exact道具,使用路线参数,例如/: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;
Run Code Online (Sandbox Code Playgroud)
最后 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;
Run Code Online (Sandbox Code Playgroud)
我认为 Gatsby 可以控制来自 CMS 的内容,但鉴于它是 SSG,我可能错了。我可能误解了仅客户端的基本原理。React 中的概念和使用 Gatsby 对我来说仍然很新,因此将不胜感激任何帮助或指导实现目标。
所以我标记的答案是“让球滚动”的答案。对 state 正在发生的事情的解释以及需要useContextor 或 redux 帮助我理解我哪里出错了。
此外,使用 Web 令牌的建议促使我找到有关在应用程序中使用 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>
</>
);
Run Code Online (Sandbox Code Playgroud)
我假设在您的 PrivateRoute 组件中,您错误地使用了 isLoggedIn 检查。从 auth.js 导入和使用 isLoggedIn 将仅在最初运行,并且不会充当监听器。您可以做的是将 isLoggedin 的值存储在全局状态变量(例如 useContext 或 redux)中,并创建一个自定义挂钩来检查登录状态。其次避免直接访问localStorage,而是使用全局状态管理(useContext,redux)或本地状态管理(useState,this.state)。注意:当您通过直接在浏览器中粘贴网址进入路线时,它总是会刷新页面并且所有存储的状态都会重新初始化。这可能就是您遇到此问题的原因。浏览器不知道您之前是否已登录,因此一旦安装您的应用程序,它总是会进行验证。您可以做的是将 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());
};
Run Code Online (Sandbox Code Playgroud)
现在在私人路线上做
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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
113 次 |
| 最近记录: |