Ссылка на один пост в react

#reactjs #react-router #fetch

Вопрос:

@edit ок, поэтому я обновляю свой код в главном приложении:

 function App() {
  return (
    <Layout>
      <Switch>
        <Route path='/' exact={true}>
          <Posts />
        </Route>
        <Route path='/favorite-posts'>
          <FavoritePosts />
        </Route>
        <Route path='/single-post:id'>
          <SinglePost />
        </Route>
        <Route>
          <Page404 path='*' />
        </Route>
      </Switch>
    </Layout>
  )
}
 

Похоже, страницы работают, но как я могу передать заголовок и текст из выборки на одну страницу?

 const Posts = () => {
  const [data, setData] = useState([])
  const [isLoading, setIsLoading] = useState(true)

  useEffect(() => {
    fetchData()
  }, [])

  // useEffect(() => {
  //   fetchImg()
  // }, [])

  const fetchData = async () => {
    let response = await fetch('https://jsonplaceholder.typicode.com/posts')
    await response
      .json()
      .then((finish) => {
        setIsLoading(false)
        setData(finish) //.splice(0, 5)
        console.log(finish)
      })
      .catch((error) => {
        console.error('Houston, we have a problem.. with fetch')
      })
  }

  //loading animation
  if (isLoading) {
    return <Loading />
  }

  return (
    <>
      <BlogPosts datas={data} />
    </>
  )
}

export default Posts


 
 const Post = ({ title, body, random, id }) => {
  const favoritesCtx = useContext(FavoritesContext)

  const itemIsFavorite = favoritesCtx.itemIsFavorite(id)

  function toggleFavoriteStatusHandler() {
    if (itemIsFavorite) {
      favoritesCtx.removeFavorite(id)
    } else {
      favoritesCtx.addFavorite({
        id: id,
        title: title,
        body: body,
      })
    }
  }

  return (
    <article className={styles.box}>
      <Link to={`/single-post:${id}`}>
        <img
          className={styles.box__image}
          // src={`https://rickandmortyapi.com/api/character/avatar/${random}.jpeg`}
          src={`https://rickandmortyapi.com/api/character/avatar/19.jpeg`}
          alt='test'
        />
      </Link>
      <button
        className={itemIsFavorite ? styles.box__btn_two : styles.box__btn}
        onClick={toggleFavoriteStatusHandler}
      >
        {itemIsFavorite ? 'Remove from Favorites' : 'Add to Favorites'}
      </button>
      <h4 className={styles.box__title}>{title}</h4>
    </article>
  )
}
 
 const SinglePost = ({ title, body, id }) => {
  return (
    <section>
      <p>{id}</p>
      <h1>{title}</h1>
      <h2>{body}</h2>
      <p>hey</p>
    </section>
  )
}

export default SinglePost
 

Я получаю и сопоставляю сообщения с https://jsonplaceholder.typicode.com/posts

У меня уже есть сообщения на моем сайте, но как я могу перейти к одному сообщению и получить уникальную информацию, я имею в виду текст и заголовок по идентификатору сообщения?

Есть идеи, как я могу это сделать?

Комментарии:

1. Что вы имеете в виду под «как я могу перейти на один пост и получить уникальную информацию», можете ли вы уточнить?

2. используйте параметр Url для передачи идентификатора вашего маршрута, например ‘/:postID’ reactrouter.com/web/example/url-params

Ответ №1:

Для этого вам нужно внести несколько изменений. Если вы хотите иметь специальную страницу для каждого поста, то SinglePost будете действовать как страница. Вам нужно будет добавить маршрут, который принимает идентификатор записи в качестве параметра и на основе этого извлекает данные для этой конкретной записи и отображает этот компонент. Что-то вроде этого:

       <Switch>
        //...
        <Route path='/post/:id'>
          <SinglePost />
        </Route>
        //...
      </Switch>
 

Теперь в SinglePost файле получите идентификатор из параметра маршрута и выполните вызов api.

 import {useParams, useState, useEffect} from 'react'
const SinglePost = (props) => {
  //this is where we will store data after getting from api
  const [post, setPost] = useState();
  // get id from route param using this hook
  const id = useParams().id;
  // then in useEffect call the api to fetch data for single post
  useEffect(()=>{
    axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`).then(res => {
   setPost(res.data);
   })
  },[])
  return (
    <section>
      <h1>{post?.title}</h1>
      <h2>{post?.body}</h2>
    </section>
  )
}

export default SinglePost;
 

Надеюсь, вы поймете картину.

Ответ №2:

Хорошо, я сделал это !

 import { useLocation } from 'react-router'
import { useEffect, useState } from 'react'
import styles from './SinglePost.module.css'
import Loading from '../ui/Loading'
import Comments from './Comments'

const SinglePost = () => {
  const location = useLocation()
  const path = location.pathname.split('/')[2]

  const [data, setData] = useState([])
  const [isLoading, setIsLoading] = useState(true)
  const [comm, setComm] = useState([])

  useEffect(() => {
    fetchData()
  }, [])

  useEffect(() => {
    fetchComment()
  }, [])

  const fetchData = async () => {
    let response = await fetch(
      'https://jsonplaceholder.typicode.com/posts/'   path
    )
    await response.json().then((finish) => {
      setIsLoading(false)
      setData(finish)
      console.log(finish)
    })
  }
  const fetchComment = async () => {
    let response = await fetch('https://jsonplaceholder.typicode.com/comments/')
    await response.json().then((finish) => {
      setIsLoading(false)
      setComm(finish.splice(0, 7)) //random
      console.log(finish)
    })
  }

  if (isLoading) {
    return <Loading />
  }

  return (
    <section className={styles.single}>
      <div className={styles.single__text}>
        <h1>{data.title}</h1>
        <p>{data.body}</p>
        <h4>Comments:</h4>
      </div>

      <div className={styles.comments}>
        {comm.map((comme) => {
          return (
            <Comments
              key={comme.id}
              name={comme.name}
              email={comme.email}
              body={comme.body}
            />
          )
        })}
      </div>
    </section>
  )
}

export default SinglePost

 

Ответ №3:

Добавьте это в свой маршрут

   <Route path='/post:id'>
          <Post />
        </Route>
 

И добавьте ссылку на свой компонент публикации для перенаправления

 <Link to={"/post" {item._id}/>