I'm trying to make a blogsite using MERN stack. So here I have my Blogs component which fetches all blogposts from db and display as shown below
here's the react code for the above pic
import { useEffect, useState } from "react";
import axios from 'axios';
import BlogDetails from "./BlogDetails";
const Blogs = () => {
const [blogPost, setPosts] = useState([])
useEffect(()=>{
const fetchBlog = async ()=>{
const blogsData = await axios('http://localhost:4000/blogs')
const blogsFetched = blogsData.data
console.log(blogsFetched);
setPosts(blogsFetched)
}
fetchBlog()
},[])
return (
<div className="blogs content">
<h2>All Blogs</h2>
{ blogPost.map((post)=>(
<div key={post._id}>
<a className="single" href={post._id}>
<h3 className="title" >{post.title}</h3>
<p className="snippet">{post.snippet}</p>
</a>
</div>
))
}
</div>
);
}
export default Blogs;
I want to show a particular blog post in detail when I click on its title from the above page.
On clicking the title, those details will be passed as props to another component named BlogDetails and will be rendered. The part where I'm stuck is routing to BlogDetails component with blogpost id. Is there any way in which on clicking the title, I can use Route to render BlogDetails component?
Please help
Assuming you're using react-router, you could do something like:
const history = useHistory();
.
.
.
<div onClick={() => history.push(`/blog/${post.id}`)}>
<h3 className="title">{post.title}</h3>
</div>
And then your router will render your component which you specified to be rendered for the /blog route. In that route, you can fetch the url using useLocation and then parse the id by splitting the url.
const { pathName } = useLocation(); // also from react-router
Alternatively (and more elegantly), you can push pieces of state when you do history.push, like:
...onClick={() => history.push(`/blog${post.id}`, { blogId: ${post.id}})}
Then again in your subsequently rendered component you use useLocation to get the state passed:
const { state } = useLocation();
yes you can use route for BlogDetail component
add BlogDetail link in BrowserRouter
<Route path={'url'} render={(props) => <BlogDetail/>}/>
In Blogs component use Link of react router dom and then use this link on title in render html like this
import { Link } from "react-router-dom";
{ blogPost.map((post)=>(
<div key={post._id}>
<a className="single" href={post._id}>
<Link to={{
pathname:'url', // this will be your url of BlogDetail
state: post //if you want post object detail in next component
}}>
<h3 className="title" >{post.title}</h3>
</Link>
<p className="snippet">{post.snippet}</p>
</a>
</div>
))
}
Related
Im learning React with routing and api calls at the moment. I've got an api were I need to find all the urls and post them on a page that was successful. But now I need to make a detail page where I can show more information about the url. Page 1 is like : gather all the urls and show them in a list. And page 2 is if you have clicked on a url in the list on page 1 you will be navigated to page 2 where a detail dialog is showed.
I have the page 1 completely and I can navigate to page 2 but I can't show any data from the api in page 2 information/detailpage.I don't know how to work with the key and get the info. I Tried several things but none of them works. Im using link.Link as key and I need description property , url , api name.
This is my page 1:
import React from "react";
import {Link, NavLink} from 'react-router-dom';
import { Detail } from './Detail';
export default class FetchLinks extends React.Component {
state = {
loading: true,
links: [],
};
async componentDidMount() {
const url = "https://api.publicapis.org/entries?category=development";
const response = await fetch(url);
const data = await response.json();
this.setState({links: data.entries, loading: false});
}
render() {
if (this.state.loading) {
return <div>loading...</div>
}
if (!this.state.links.length) {
return <div>geen links gevonden</div>
}
return (
<div>
{this.state.links.map(link => (
<div key={link.Link}>
<ul><li>
<p>
<NavLink to={`/Detail/${link.Link}`}>
{link.Link}
</NavLink>
</p>
</li></ul>
</div>))}
</div>
);
}
}
this is page 2:
import React from 'react';
import Content from './Content';
const Detail = () =>{
return(
<div>
<h1>Detail Page</h1>
<p>{this.state.links.Link}</p>
</div>
)
}
export default Detail();
This is how it should be
So if I understood correctly, you have all your data in page 1 and need to pass the data to page 2. For this you have to write your NavLink like this:
<NavLink to={{
pathname: `/Detail/${link.Link}`,
state: link.Link
}}>
{link.Link}
</NavLink>
Now you can use UseLocation hook of react-router to access this state that you just passed. So in page 2:
import React from 'react';
import { useLocation } from "react-router-dom";
const Detail = () =>{
const location = useLocation();
return (
<div>
<h1>Detail Page</h1>
<p>{location.state.link}</p>
</div>
);
}
export default Detail();
You can read more about react-router hooks here.
I've created a dynamic routing for a ProductDetail page (each Restaurant has its own details that should be shown on this page). the routing is working but I don't get any data and I can't figure out the right way to get data from firestore by the Id of each restaurant.
PS: the product details are rendering in the console but the problem still how to display to the detailpage
ProductDetail.js
import { firestore } from "../../../../../fire";
import {useParams} from "react-router-dom";
import {useEffect} from "react";
import {useState} from "react";
import {Fragment} from "react";
function ProductDetail() {
const {productId}= useParams();
const [product,setProduct]=useState();
useEffect( () => {
firestore
.collection("Restaurants")
.doc(productId).get()
.then( doc => {
console.log(doc.data());
setProduct(doc.data());
});
}, () => {
}
);
return (
<div className="col-12">
<div className="card">
<h1>{product.name_restaurant} </h1>
<p>Price:$</p>
{/* <p>{product.email}</p> */}
</div>
</div>
);
}
export default ProductDetail;
this my console : all details of the restaurant are returned
Still cannot return details on my page
I got this error
This happens because when you first render the component your product state variable is null, then you make the API call in the useEffect, your state variable is populated and the component is re-rendered, but at that point, you already have the error. To fix it, you just have to render your markup when the product is ready to be rendered (not null)
return product ? (
<div className="col-12">
<div className="card">
<h1>{product.name_restaurant} </h1>
<p>Price:$</p>
{/* <p>{product.email}</p> */}
</div>
</div>
) : <div>Loading...</div>;
SOLVED By adding an ? to product and that's to check undefined {product?.name_restaurant}
I'm working with Nextjs for the first time.
I'm trying to create multiple layouts which will consist on a <Header><different-layouts-for-each><Footer> structure.
The issue that I'm facing is that getStaticProps or getServerProps can run at the page level only.
Since I need SEO on the navigation I suppose I should get it's props on every single page file using one of the two mentioned methods.
The problem here is that I'd have to get the menu props on each one of the pages, but having different templates I will have to repeat myself on all of them in order to bring the content statically or prerendered and be SEO readable.
Getting the menu props on the <MainNav> component would be the ideal situation.
I tried doing an asnyc/await on the component:
<Header> component
import Logo from "../components/header/logo";
import MainNav from "../components/header/mainnav.js";
function Header() {
return (
<div className="headwrapper container mx-auto py-8 flex items-center">
<Logo />
<MainNav/>
</div>
);
}
export default Header;
<MainNav> component
import Link from "next/link";
import { WpHeader } from "../../lib/wpapi";
import React, { useEffect, useState } from "react";
function MainNav() {
const [nav, setNav] = useState(0);
useEffect(() => {
const fetchData = async () => {
const wp = new WpHeader();
const call = await wp.getAxiosMenu();
console.log(call);
setNav(call);
};
fetchData();
}, []);
return (
<div className="navigation text-right w-3/4">
<ul className="main-navigation">
{nav
? nav.map(item => (
<li key={item.id} className="inline-block mx-2">
<Link href={item.path}>
<a>{item.label}</a>
</Link>
</li>
))
: "loading"}
</ul>
</div>
);
}
export default MainNav;
The issue here is that this will return a promise and the html will show "loading" instead of the actual menu html.
Any help or article that could help me on this?
Thanks.
I've made a quick CodeSandBox example what I am after. I have a "Our Courses" section on the landing page with the button "Read more". Once the "Read more" button gets clicked, depending on the Course it would render that information. Now I got the button to work but now I am stuck and can't figure out how to pass relevant information to the redirected page. Now let's say I want to get the Course "Title" and "Description" get passed onto to the redirected page. How can I do that?
CodeSandBox link here - Link here
Your CardInfo component can look-up the course detail from your courses repository.
To perform the look-up you can determine which card was selected by using the react-router useParams hook; this allows you to determine which course identifier was passed via the selected route i.e.
import React from "react";
import courses from "./courses";
import { useParams } from "react-router-dom";
const CardInfo = () => {
const { id } = useParams();
const course = courses.find(course => course.id === id);
return (
<div>
<h1>{course.title}</h1>
<p>{course.description}</p>
</div>
);
};
export default CardInfo;
A complete working example of this can be seen here (its a fork of your CodeSandBox).
You can pass data between Routes by using the object version of the to prop of Link component, so change your Link component to this:
//Card.jsx
<Link
to={{
pathname: `/card/${course.title}`,
state: {
description: course.description
}
}}>
<button className="btn">Read more</button>
</Link>
Then in your CardInfo.jsx component you can access this data by props.location.state.description
import React from "react";
const CardInfo = (props) => {
console.log(props)
return (
<div>
<h1>
How can I pass course title here depending on which button I click
</h1>
<p>{props.location.state.description}</p>
</div>
);
};
export default CardInfo;
Hope it helps :)
In your CardInfo component you can access the id provided by the route using the useParams from your react-router-dom library.
I'm using your <Route path="/card/:id" component={CardInfo} /> for reference.
Implement it like this:
import React from 'react'
import { useParams } from 'react-router-dom'
const CardInfo = () => {
const { id } = useParams()
return <div>Card ID: {id}</div>
}
export default CardInfo
Now that you've got the id you should be able to use it for whatever you need.
There are multiple approaches to pass this data:
You can pass data through the link state like this:
<Link
to={{
pathname: `/card/${course.title}`,
state: { description: course.description }
}}
>...</Link>
And then read it in the CardInfo component like this:
import { useLocation } from "react-router-dom";
const CardInfo = () => {
const location = useLocation();
console.log(location.state) // { description: 'Lorem ipsum...' }
However, the best way to do this is to pass the course id in the URL and read the rest of the information from the courses.js file:
This is already correct, you accept the course id as URL paramter:
<Route path="/card/:id" component={CardInfo} />
Pass the course id in the link:
<Link to={`/card/${course.id}`}>
Read the id parameter from the URL and get the rest of the course information from the courses file:
import { useParams } from "react-router-dom";
import courses from './courses'
const CardInfo = () => {
const params = useParams();
console.log(courses[params.id]);
I want to go to other pages in my react project using a router-react-dom. I created a function like this:
const {id} = props;
const redirect = () => {
console.log("redirecting...");
const url = `/${id}`;
return <Redirect to={url} />;
};
Then I make props to other component like this:
<BtnDetalii
clickFn={redirect}
text="apasa aici pentru mai multe detalii"
/>
and this is my btnDetalii component
const BtnDetalii = props => (
<div onClick={() => props.clickFn()} className="detalii">
{props.text}
</div>
);
When I click the buton doesn't work. What I missed?
You can use React Router v4. Wrap your component with withRouter from react-router-dom and this way you can access history prop. After that you can push new url to your history prop.
I am not sure what is your code in the parent component where your redirect function is, but this is a simple example using withRouter. If you share more of your component I can change the snippet and add your code.
import React from "react";
import { withRouter } from "react-router-dom";
import BtnDetalii from "./BtnDetalii";
const Card = withRouter(({ history, ...props }) => {
const redirect = () => {
console.log("redirecting...");
const id = props.id;
const url = `detalii/${id}`;
history.push(url);
};
return (
<div className="today">
<div className="data">{props.nume}</div>
<img src={props.poza} className="img-icon" alt="poza" />
<p className="text">{props.strada}</p>
<BtnDetalii
clickFn={redirect}
text="apasa aici pentru mai multe detalii"
/>
</div>
);
});
export default Card;
Check this example for functional component and you can go through documentation for better understanding.
React router dom for functional component
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}