javascript React.js使用Slug从API数据渲染新页面,(点击文章列表中的一篇文章,然后直接进入该文章所在的页面)

5vf7fwbs  于 2023-01-04  发布在  Java
关注(0)|答案(1)|浏览(102)

问题是-(试图解决点击文章列表中的一篇文章然后将用户引导到该特定文章进行阅读的问题)需要使用slug从API调用呈现新页面。AllPosts页面列出不同的文章。它需要文章列表中的图像上的可点击链接来引导到具有该文章的OnePost页面,使用来自API的数据。我已经从BlogCard组件开始,其中我使用了一个Link组件,该组件包含文章列表中的Title和Image。Link组件的目的地为{/posts/${slug}}〉。下一部分是尝试管理App.js页面上的路由,或者对于期望的结果是否存在对此的更有效的解决方案(或者如果有人选择了更好的方法来做这件事)。最后,在OnePost页面上(这篇文章就是针对它编写的)我已经开始进行API调用,目的是使它与AllPost组件相同(使用AXIOS与graphQL模式),到目前为止几乎没有成功。OnePost页面将显示文章标题和封面图片。我已经包括了一个沙箱链接跟随。并留下了注解掉的代码,所以它不会被打破。它在哪里它将显示从API数据的所有帖子页面上的文章列表。提前感谢这么多,我希望这一切都是有意义的,任何帮助或方向将不胜感激...............再次感谢-Python🐍🏴‍海盗️😃................沙箱链接-----〉https://codesandbox.io/s/2-1-23-react-slug-link-3ncqli?file=/src/components/BlogCard.js

import React from "react";
import { Link } from "react-router-dom";
import "./styles.css";

const BlogCard = ({ coverPhoto, title }) => {
  return (
    <div className="card">
      <Link to={`/posts/${slug}`}>
      <h2>{title}</h2>
      <img
        src={coverPhoto ? coverPhoto.url : null}
        alt=""
        height={200}
        width={200}
      ></img>
      </Link>
    </div>
  );
};
export default BlogCard;
import React from "react";
import { useQuery } from "react-query";
 import axios from "axios";

const endpoint =
   "";

 const QUERY = `
  {
     posts {
       id
       title
       slug
       coverPhoto {
         id
         url
       }
     }
   }
 `;
 const SLUGLIST = `
   {
     posts {
       slug
     }
   }
 `;

const OnePost = ({ post }) => {
  return (
    <div>
      <h1>One Post Page</h1>
      <img
        src={post.coverPhoto ? post.coverPhoto.url : null}
        alt=""
        height={200}
        width={600}
      ></img>
     <h2>{post.title}</h2>
    </div>
  );
};

export default OnePost;
import React from "react";
import { useQuery } from "react-query";
import axios from "axios";
import BlogCard from "../../components/BlogCard";

const endpoint =
  "";

const QUERY = `
{
  posts {
    id
    title
    slug
    coverPhoto {
      createdBy {
        id
      }
      url
    }
  }
}
`;

const AllPosts = () => {
  const { data, isLoading, error } = useQuery("blog_posts", async () => {
    const response = await axios({
      url: endpoint,
      method: "POST",
      data: {
        query: QUERY
      }
    });
    return response.data.data;
  });

  if (isLoading) return "Loading...";
  if (error) return <pre>{error.message}</pre>;

  return (
    <div>
      <h1>Top Web Development Resources 2023</h1>
      <ul>
        {data.posts.map((post) => (
          <BlogCard
            title={post.title}
            key={post.id}
            coverPhoto={post.coverPhoto}
          />
        ))}
      </ul>
    </div>
  );
};

export default AllPosts;
import React from "react";
import { QueryClient, QueryClientProvider } from "react-query";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import AllPosts from "./Pages/AllPosts/AllPosts";
import OnePost from "./Pages/OnePost/OnePost";

const queryClient = new QueryClient();

const App = () => (
  <>
    <Router>
      <Switch>
    <QueryClientProvider client={queryClient}>
      <Route path="/" component={AllPosts} />
          <Route path="/onepost" component={OnePost} />
      <AllPosts />
    </QueryClientProvider>
    </Switch>
    </Router>
  </>
);

export default App;

这两张图片是使用相同数据的帖子列表和单个帖子的示例。

wgeznvg7

wgeznvg71#

由于两个页面/组件之间的数据是相同的,因此我建议在父组件中提取一次,并通过React上下文将其提供给后代。
创建一个布局路径来获取帖子并通过Outlet组件的上下文提供,这实际上只是将获取逻辑从AllPosts移动到一个新的布局路径组件。

import { QueryClient, QueryClientProvider, useQuery } from "react-query";
import axios from "axios";
import {
  BrowserRouter as Router,
  Routes,
  Route,
  Navigate,
  Outlet
} from "react-router-dom";
import AllPosts from "./Pages/AllPosts/AllPosts";
import OnePost from "./Pages/OnePost/OnePost";

const queryClient = new QueryClient();

const endpoint =
  "https://api-ap-southeast-2.hygraph.com/v2/clcdbkbxr45xk01tcdpxgg3sh/master";

const QUERY = `
{
  posts {
    id
    title
    slug
    coverPhoto {
      createdBy {
        id
      }
      url
    }
  }
}
`;

const PostsLayout = () => {
  const { data, isLoading, error } = useQuery("blog_posts", async () => {
    const response = await axios({
      url: endpoint,
      method: "POST",
      data: {
        query: QUERY
      }
    });
    return response.data.data;
  });

  if (isLoading) return "Loading...";
  if (error) return <pre>{error.message}</pre>;

  return <Outlet context={{ posts: data.posts }} />;
};

渲染布局管线以包裹两条现有管线。

const App = () => (
  <QueryClientProvider client={queryClient}>
    <Router>
      <Routes>
        <Route path="/posts" element={<PostsLayout />}>
          <Route index element={<AllPosts />} />
          <Route path=":id" element={<OnePost />} />
        </Route>
        <Route path="*" element={<Navigate to="/posts" replace />} />
      </Routes>
    </Router>
  </QueryClientProvider>
);

更新AllPposts以使用useOutletContext钩子访问提供的posts上下文值。

import BlogCard from "../../components/BlogCard";
import { useOutletContext } from "react-router-dom";

const AllPosts = () => {
  const { posts } = useOutletContext();

  return (
    <div>
      <h1>Top Web Development Resources 2023</h1>
      <ul>
        {posts.map((post) => (
          <BlogCard {...post} key={post.id} />
        ))}
      </ul>
    </div>
  );
};

更新BlogCard以正确呈现指向详细信息路径的链接。

import { Link } from "react-router-dom";

const BlogCard = ({ coverPhoto, id, title }) => {
  return (
    <div className="card">
      <Link to={`/posts/${id}`}>
        <h2>{title}</h2>
        <img
          src={coverPhoto ? coverPhoto.url : null}
          alt=""
          height={200}
          width={200}
        />
      </Link>
    </div>
  );
};

更新OnePost以访问id路由路径参数和posts数组,并通过id查找匹配的post。

import { useOutletContext, useParams } from "react-router-dom";

const OnePost = () => {
  const { id } = useParams();
  const { posts } = useOutletContext();

  const post = posts.find((post) => post.id === id);

  if (!post) {
    return <div>No post.</div>;
  }

  return (
    <div>
      <h1>One Post Page</h1>
      <img
        src={post.coverPhoto ? post.coverPhoto.url : null}
        alt="cover art"
        height={200}
        width={600}
      />
      <h2>{post.title}</h2>
    </div>
  );
};

相关问题