How to use slug url in nextjs - javascript

I am working in nextjs, i am trying to make "dynamic routes",
i want after click my url should be like "myurl.com/article/55"
for this i use following "link tag"
<Link href={{pathname: "article/[id]",query: { id: post.id },}}>
<a className="rdmre-btn"> Read More</a>
</Link>
And here is my code in ("pages/article/[slug].js) in file,Where i am wrong ? i want whenever i click on any blog then blog details page should open.
import Axios from "axios";
import { useRouter } from "next/router";
import Link from "next/link";
import LatestBlogs from "../../components/LatestBlogs/LatestBlogs";
const Post = ({ post }) => {
const router = useRouter();
const htmlString = post.description_front;
if (router.isFallback) {
return <div>Loading...</div>;
}
return (
<>
<header className="bgbanner blog_header">
<div className="container cont">
<div className="header">
</div>
</div>
<div className="container "></div>
</header>
<section>
<div className="container Blog_page_sidebar">
<div className="blog_details">
<div className="blog_image">
<img src={post.image} />
</div>
<div className="blog_heading">
<h2>{post.title}</h2>
</div>
<div className="blog_detail">
<div
className="product-des"
dangerouslySetInnerHTML={{ __html: htmlString }}
/>
</div>
</div>
</div>
</section>
</>
);
};
export default Post;
export const getStaticProps = async ({ params }) => {
const { data } = await Axios.get(
`https://myurl.com/api/blogbyids/${params.id}`
);
const post = data;
return {
props: {
post,
},
};
};
export const getStaticPaths = async () => {
const { data } = await Axios.get(
"myurl.com/admin-panel/api/blogs"
);
const posts = data.slice(0, 10);
const paths = posts.map((post) => ({ params: { id: post.id.toString() } }));
return {
paths,
fallback: true,
};
};

[slug] is used to have nested routes. But correct is [...slug].js (info)
Example: myurl.com/article/[id]/[otherid]
In the example above we can see that in [id] can be nested children. You can name this param as you want.
If you want to have your structure as myurl.com/article/55, you need to have structure as follow:
In your pages folder:
You create a folder article (pages/article)
You create 2 files: index.js (or .tsx) and [id].js (you can name as [slug].js or [specialId].js - no matter the name
After, you are getting info with param name created.
Here is example of the code (URL: myurl.com/article/55; file: pages/article/[pid].js)
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
//same name as name of your file, can be [slug].js; [specialId].js - any name you want
const { pid } = router.query
//result will be '55' (string)
return <p>Post: {pid}</p>
}
export default Post

Related

How do I route to individual pages using index number instead of id of the object?

I am quite new to useParams and ExpressJS and am trying to use it to display a detailed user profile after clicking on a list of profiles tagged with their profile number. The user profiles are an object stored in an array. I am trying to get the link in the browser to display it as "https://localhost/3000/profile/1" where 1 is the index number instead of the profile number like "https://localhost/3000/profile/A123".
Data is being stored in profile.json:
[{"PROFILE_NUMBER": "A123", "NAME": "X", "AGE" : "21", "HOBBY" : "RUN"} , .....]
In the utils.js
const getProfiles = async () => {
// Retrieve sightings.json file contents as string
const profiles = await readFile("./profiles.json", "utf8");
// Return sightings as an object
return JSON.parse(profiles);
};
module.exports = {
getProfiles
}
Here is my index.js in my backend folder
const express = require("express");
const { getProfile } = require("./utils.js");
var cors = require("cors");
require("dotenv").config();
const PORT = process.env.PORT;
const app = express();
app.use(cors());
app.get("/profiles", async (req, res) => {
const profiles = await getProfile();
res.json(profiles);
});
app.get("/profiles/:profileIndex", async (req, res) => {
const profiles = await getProfile();
res.json(profiles[req.params.profileIndex]);
});
app.listen(PORT, () => {
console.log(`Express app listening on port ${PORT}!`);
});
On the other hand, for my frontend.
This is my App.js where the data is being called from the backend:
import React from "react";
import "./App.css";
import Card from "./Card";
import Single from "./Single";
import { Routes, Route } from "react-router-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
profiles: [],
};
}
componentDidMount() {
fetch("http://localhost:3000/profiles")
.then((response) => response.json())
.then((data) => {
this.setState({ profiles: data });
});
}
render() {
return (
<div className="App">
<Routes>
<Route
exact
path="/profile"
element={<Card profiles={this.state.profiles} />}
></Route>
<Route
path="/profiles/:profileIndex"
element={<Single profiles={this.state.profiles} />}
></Route>
</Routes>
</div>
);
}
}
export default App;
This is my Card.js which is the list of user profiles displayed.
import React from "react";
import "./App.css";
import { Link } from "react-router-dom";
const Card = ({ profiles }) => {
return (
<div className="App">
{profiles.map((profile) => (
<div className="container">
<Link
style={{ display: "block", margin: "1rem 0" }}
to={`/profiles/${profile.PROFILE_NUMBER}`}
key={profile.PROFILE_NUMBER}
>
<div>
{profile.PROFILE_NUMBER}
<br />
{profile.NAME}
<br />
</div>
</Link>
</div>
))}
</div>
);
};
export default Card;
Lastly, this is the Single.js where it display individual profile
import React from "react";
import { useParams } from "react-router-dom";
import "./App.css";
const Single = ({ profiles }) => {
let params = useParams();
var newArray = profiles.filter(function (el) {
return el.PROFILE_NUMBER === params.profileIndex;
});
return (
<div className="App">
{console.log(newArray)}
{`Report Number: ${newArray[0].PROFILE_NUMBER}`}
<br />
{`County: ${newArray[0].NAME}`}
<br />
{`Year: ${newArray[0].AGE}`}
<br />
{`Description: ${newArray[0].HOBBY}`}
</div>
);
};
export default Single;
How do I get the link to display index number and show the correct user profile instead of using the profile number? Any guidance on how to implement a search function too? Thank you!
If you want the profileIndex route path param to be the profiles array index instead of the specific profile number of an element in the array then pass the mapped index in the link and use the profileIndex param as the array index when pulling a profile object from the array.
Example:
const Card = ({ profiles }) => {
return (
<div className="App">
{profiles.map((profile, index) => (
<div className="container">
<Link
style={{ display: "block", margin: "1rem 0" }}
to={`/profiles/${index}`} // <-- pass array index here
key={profile.PROFILE_NUMBER}
>
<div>
{profile.PROFILE_NUMBER}
<br />
{profile.NAME}
<br />
</div>
</Link>
</div>
))}
</div>
);
};
...
const Single = ({ profiles }) => {
const { profileIndex } = useParams();
const profile = profiles[profileIndex];
if (!profile) {
return "No Profile";
}
return (
<div className="App">
{`Report Number: ${profile.PROFILE_NUMBER}`}
<br />
{`County: ${profile.NAME}`}
<br />
{`Year: ${profile.AGE}`}
<br />
{`Description: ${profile.HOBBY}`}
</div>
);
};

Error: A required parameter (Slug) was not provided as a string in getStaticPaths for /post/[Slug] [duplicate]

This question already has an answer here:
Error: A required parameter (slug) was not provided as a string in getStaticPaths for /posts/[slug]
(1 answer)
Closed 6 months ago.
hey I start a tutorial on Build and Deploy THE BEST Modern Blog App with React | GraphQL, NextJS, Tailwind CSS and it shows me this error I don't know how to fix it and it shows me only when I try to enter post
this is the error :
Error: A required parameter (Slug) was not provided as a string in getStaticPaths for /post/[Slug]
this is the code :
import React from 'react';
import { useRouter } from 'next/router';
import { PostDetail, Categories, PostWidget, Author, Comments, CommentsForm, Loader } from '../../components';
import { getPosts, getPostDetails } from '../../services';
const PostDetails = ({post}) => {
console.log({post});
if (router.isFallback) {
return <Loader />;
}
return (
<>
<div className="container mx-auto px-10 mb-8">
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
<div className="col-span-1 lg:col-span-8">
<PostDetail post={post} />
<Author author={post.author} />
<CommentsForm slug={post.slug} />
<Comments slug={post.slug} />
</div>
<div className="col-span-1 lg:col-span-4">
<div className="relative lg:sticky top-8">
<PostWidget slug={String(post.slug)} categories={post.categories.map((category) => String(category.slug))} />
<Categories />
</div>
</div>
</div>
</div>
</>
);
};
export default PostDetails;
export async function getStaticProps({ params }) {
const data = await getPostDetails(String(params.slug));
return {
props: {
post: data,
},
};
}
export async function getStaticPaths() {
const posts = await getPosts();
return {
paths: posts.map(({ node: { slug } }) => ({ params: {slug}})),
fallback: true,
};
}
Error is here
paths: posts.map(({ node: { slug } }) => ({ params: {slug}})),
if you used like this, your dynamic page name should me [slug]. For example if your dynamic page is [id].js you should have
paths: posts.map(({ node: { slug } }) => ({ params: {id}})),

Not able to change the state on clicking between different categories in moviedb-app

So I want to toggle between different categories in my react movie-app such as Trending,Top Rated,Popular etc.I am use useState hook for this,by making the initial state as one category then changing the state through the onClick event on the buttons.But it doesn't seem to be working.What could be the problem?
Code:
App.js
import { useState } from "react";
import Movie from "./components/Movie";
import requests from "./components/ApiRequest";
import Navbar from "./components/Navbar";
function App() {
const [category, setCategory] = useState('top_rated')
return (
<div className="App">
<Navbar setCategory={setCategory} />
<div className="movie-container">
<Movie fetchUrl={"movie/" + category + "?api_key=" + API_KEY + "&language=en-US&page=1"} />
</div>
</div>
);
}
export default App;
Navbar.js
import React from 'react'
import SearchBar from './SearchBar'
import { FiFilter } from 'react-icons/fi'
const Navbar = ({ setCategory }) => {
return (
<div className="navbar-container">
<button className="navbar-btn"><FiFilter />Filter</button>
<div className="categories">
<button className="cat-btn" onClick={() => setCategory("popular")}>Popular</button>
<button className="cat-btn" onClick={() => setCategory("top_rated")}>Top Rated</button>
<button className="cat-btn" onClick={() => setCategory("upcoming")}>Upcoming</button>
</div>
<SearchBar />
</div>
)
}
export default Navbar
Movie.js
const Movie = ({ fetchUrl }) => {
const [movie, setMovie] = useState([]);
useEffect(() => {
async function getPost() {
const response = await client.get(fetchUrl);
console.log(response);
setMovie(response.data.results);
// return response;
}
getPost();
}, [])
return (
movie.map((m) => (
<div className="movie-component" key={m.id}>
<img src={`https://image.tmdb.org/t/p/w500${m.backdrop_path}`} alt="" />
<div className="metadata">
<h1>{m.title}</h1>
<a>⭐{m.vote_average}</a>
</div>
</div>
)
))
}
So I have initialized the useState hook in App.js and then using it in Navbar.js as the set the state of this hook on click event.
useEffect(() => {
async function getPost() {
const response = await client.get(fetchUrl);
console.log(response);
setMovie(response.data.results);
// return response;
}
getPost();
}, [fetchURL])
please update your dependency array as follows.
on changing the category, fetchURL value is being changed.
so it need to be included in dependency array of useEffect Hook.

Failed to compile: Module not found: Can't resolve in ReactJS

I was about rounding up this activity and I started getting this error:
Module not found: Can't resolve './components/Post' in ./src/pages/index.js
I have tried all I could but was not able to solve this problem. Below is the list of my codes:
index.js
import React, { useState, useEffect } from 'react';
import Posts from './components/Pagination';
import Pagination from './components/Post';
import axios from 'axios';
const Home = () => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [postsPerPage] = useState(10);
useEffect(() => {
const fetchPosts = async () => {
setLoading(true);
const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
setPosts(res.data);
setLoading(false);
};
fetchPosts();
}, []);
// Get current posts
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);
// Change page
const paginate = pageNumber => setCurrentPage(pageNumber);
return (
<div
style={{
display: 'flex',
height: '90vh'
}}
>
<img src={require('../images/top_img.jpg')} alt='logo' height='500px' width='100%'/>
<div className='container mt-5'>
<h1 className='text-primary mb-3'>LATEST NEWS</h1>
<Posts posts={currentPosts} loading={loading} />
<Pagination
postsPerPage={postsPerPage}
totalPosts={posts.length}
paginate={paginate}
/>
</div>
</div>
);
};
export default Home;
Post.js
import React from 'react';
const Posts = ({ posts, loading }) => {
if (loading) {
return <h2>Loading...</h2>;
}
return (
<ul className='list-group mb-4'>
{posts.map(post => (
<li key={post.id} className='list-group-item'>
{post.title}
</li>
))}
</ul>
);
};
export default Posts;
Pagination.js
import React from 'react';
const Posts = ({ posts, loading }) => {
if (loading) {
return <h2>Loading...</h2>;
}
return (
<ul className='list-group mb-4'>
{posts.map(post => (
<li key={post.id} className='list-group-item'>
{post.title}
</li>
))}
</ul>
);
};
export default Posts;
Below is the structure of my code:
I believe your object names are swapped.
Isn't there an error of relative path?
import Posts from '../components/Pagination';
import Pagination from './components/Post';
both imports are in the same file and both files are in the same folder, but one has ../ and other ./
First, you I would make the named imports match the file structure:
import Post from "./components/Post"
import Pagination from "./components/Pagination"
Also, your default exports are messing things up as well. You will want to export Pagination and then in ./Post you want to export Post.
Lastly, your paths were messed up. The "components" folder is on the same level as index.js. Thus, you can access it through "./components"

React, Adding data from json to single post component

I try to write website in React and that was going fine until now. I totally got stuck.
I have component with list of posts which is working fine. My problem is, that I dont know how to add data from JSON to single post component. I was trying to change geting my JSON data from list articles component to app.js and then passing it down to component with my list posts and to single post component, but then I have error with map() function.
//geting data from JSON and passing it through props down
import React, { useEffect, useState } from "react";
import "./style.css";
import SideBar from "../SideBar";
import MainContent from "../MainContent";
import blogData from "../../assets/data/blog.json";
const MainContainer = () => {
const [posts, setPosts] = useState([]);
useEffect(() => {
const post = blogData.data;
setPosts(post);
}, []);
return (
<div className="main-container">
<MainContent posts={posts} />
<SideBar posts={posts} />
</div>
);
};
export default MainContainer;
//mapping through posts
import React from "react";
import "./style.css";
import Post from "../Post";
const MainContent = ({ posts }) => {
return (
<main className="main-content">
{posts.map(post => {
return <Post key={post.id} post={post} />;
})}
</main>
);
};
export default MainContent;
//Post from list of posts
const Post = ({ post }) => {
return (
<div className="post">
<Animated
animationIn="bounceInLeft"
animationOut="fadeOut"
isVisible={true}
>
<h3 className="postTitle">{post.blogTitle}</h3>
<div className="imgContainer">
<img
alt="travel"
src={require("../../assets/img/" + post.blogImage)}
></img>
</div>
<p className="postDescription">{post.blogText}</p>
<NavLink to={`/post/${post.id}`}>
<h5 className="postLink">Read more</h5>
</NavLink>
<h5 className="posteDate">
Posted on {post.postedOn} by {post.author}
</h5>
</Animated>
</div>
);
};
export default Post;
Here is link to my repo:
https://github.com/Gitarrra92/travel-blog/
I think I should have a state in my component with single object of specific id. I just still dont know how to do this. This is my SinglePost component
const SinglePost = ({ match }) => {
const [singlePosts, setSinglePost] = useState({});
useEffect(() => {
const singlePost = blogSingleData.data;
setSinglePost(singlePost);
console.log(singlePost);
}, [match]);
return (
<>
<Socials />
</>
);
};
export default SinglePost;

Categories