Router replace function is not working with Reactjs - javascript

I am working in Reactjs and using nextjs,Right now my current url is
"http://localhost:3000/the-trailer-was-released/pinned"
which is not working because i added "pinned",I added for "identifier" (want to use different api in serversideprops)
So for remove "pinned" i use following code
const blogs2 = Array.isArray(blogs) ? blogs : [];
const router = useRouter();
useEffect(()=>{
if(router.query?.form === 'pinned')
{
router.replace('/', undefined, { shallow: true });
}
},[blogs2])
Here is my code for serversideprops
export const getServerSideProps = async ({ params }) => {
// if url containing "pinned" then want any value in paramter,so i can hit different api
};

Related

How to pass additional parameter with dynamic routes in Reactjs

I am working in Reactjs and using nextjs,My [slug.js] is working fine with following url
<Link href={`/${post.slug}`}><a>
But i want to send/pass "hidden"(additional parameter) with this,whenever i try to do then i am getting 404 error,I want this because in some page i want to use different api in "serversideprops",Right now here is my code
export const getServerSideProps = async ({ params }) => {
console.log(params); // right now i am getting "slug" as parameter
if(params.anotherparamter)
{
//futher code
}
elseif(params.slug){
const { data: data2 } = await Axios.get(`https://xxxxxxxxxxxxxxxxxxxxxxxxx/${params.slug}`);
}
const blogs = data2;
return {
props: {
blogs: blogs
},
};
};
You can use the as prop to hide the query string.
Your link would look something like this
<Link href={`/${post.slug}?myparam="mysecret"`} as={`/${post.slug}`}></Link> //The link will not show the query param when redirected
You will then be able to access the myparam query in your serverSideProps like so.
export const getServerSideProps = async ({ params, query }) => {
...
const { myparam } = query
console.log(myparam) // will return mysecret as a string
You can read more from the docs

How to pass data in slug.js Reactjs

I am new in Nextjs, i am trying to integrate [slug.js] page, i want to know that how can we manage/get data in sidebar (similar blogs) ? in other words for blog details i used "get static path" and "props", But now i want to pass "current slug" ( to API) so i can fetch all blogs with this blog category,How can i do this ?
Client-side approach:
Since you pass the post as page-props via getStaticProps, you can either take the slug from there (if it's included in your data model), or extract the slug from the url via next's useRouter hook in case you want to do client-side fetching:
import axios from "axios"; // using axios as an example
import { useRouter } from "next/router";
const Component = () => {
const [similarPosts, setSimilarPosts] = useState([]);
const router = useRouter();
const { slug } = router.query;
const getSimilarPosts = async () => {
if (!router.isReady() || !slug) return [];
const { data } = await axios.get("/api/similar-posts-route/" + slug);
return data;
};
useEffect(() => {
if (similarPosts.length > 0) return;
(async () => {
const posts = await getSimilarPosts(); // assuming API returns an array of posts as data.
setSimilarPosts(posts);
})();
}, []);
return <div>Similar posts: {JSON.stringify(similarPosts)}</div>;
};
[...]
Server-Side approach (preferred):
I believe it would be a better approach to directly fetch similar posts inside getStaticProps to reduce API calls and for a better UX.
Inside getStaticProps you can take the slug from context.params and fetch all similar posts directly from your database/CMS, and pass them directly as props to your page component:
export async function getStaticProps({ params }) {
const { slug } = params;
// fetch similar posts directly from the database using the slug (don't call the API, it's not up yet during build phase)
const similarPosts = await executeDatabaseQueryForSimilarPosts(slug);
// [...] fetch the rest of the page props
return {
props: {
similarPosts,
// [...] return the rest of page props
},
revalidate: 60 * 30 // re-fetch the data at most every 30 minutes, so the posts stay up to date
};
}
// directly take all similar posts from props
const Component = ({similarPosts}) => {
return <div>Similar posts: {JSON.stringify(similarPosts)}</div>;
};

How to fetch Strapi by slug, and how to populate the categories

I'm trying to fetch post for a react blog with strapi backend using the slug.
I created the custom route and custom controller, but the value returned is missing a few attributes like images and category.
When I fetch using post Id, I use query string to populate the object returned, but I don't know how to had qs to the slug API route.
Below is the custom controller, and the custom route
///custom controller
async findOne(ctx) {
const { slug } = ctx.params;
const { query } = ctx;
const entity = await strapi.service('api::article.article').findOne(slug, query);
const sanitizedEntity = await this.sanitizeOutput(entity, query);
return this.transformResponse(sanitizedEntity);
}
///Custom Route
{
method: 'GET',
path: '/articles/slug/:slug',
handler: 'custom-controller.findOne',
config: {
policies: []
},
This is how I fetch from client in useEffect
useEffect(()=>{
const fetchData = async()=>{
// const query = qs.stringify({
// populate: '*',
// }, {
// encodeValuesOnly: true,
// });
const res = await axios.get(`http://localhost:1337/api/articles?filters[slug][$eq]=${slug}`)
console.log(res.data)
updateState(res.data)
}
fetchData()
setLoading(false)
}, [slug])
I've also tried to use the Entity API Service, but I just couldn't get it to work.
How do I populate the object to include these missing attributes?
With Strapi v4 you can do it this way
1. Create a file in src/api/article/_custom.js
Please note I put an underscore because:
Routes files are loaded in alphabetical order. To load custom routes before core routes, make sure to name custom routes appropriately (e.g. 01-custom-routes.js and 02-core-routes.js).
Source: https://docs.strapi.io/developer-docs/latest/development/backend-customization/routes.html#creating-custom-routers
module.exports = {
routes: [
{
method: 'GET',
path: '/articles/:slug',
handler: 'article.findOne',
config: {
auth: false
},
}
]
}
2. Edit the src/api/article/controllers/article.js
'use strict';
/**
* article controller
*/
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::article.article', ({ strapi }) => ({
// Query by slug
async findOne(ctx) {
// thanks to the custom route we have now a slug variable
// instead of the default id
const { slug } = ctx.params;
const entity = await strapi.db.query('api::article.article').findOne({
where: { slug }
});
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
return this.transformResponse(sanitizedEntity);
},
}));
Now you can call your api this way:
http://localhost:1337/api/articles/my-beautiful-article-about-orange
Reference: https://www.youtube.com/watch?v=OVV0CfgX6Qk
Note: In the video, custom.js is loaded before post.js ^^

Next JS and Vercel - development vs production

I’ve built a basic movie DB app in Next JS to see how the framework works. It’s an app that allows you to perform CRUD operations to firebase, utilising the NextJS API endpoints.
I have the app working fine in development, however it does not work at all once to Vercel. I was wondering if anyone can shed some light?
Here is the first 'get all data' call upon initialisation. The other API calls follow the same pattern. None work once deployed.
My index page has this getInitialProps function…
Home.getInitialProps = async () => {
const categories = await getCategories()
const movies = await getMovies()
const images = movies.map(movie => {
return {
id: `image-${movie.id}`,
url: movie.cover,
name: movie.name
}
})
return {
movies,
images,
categories
}
}
This fires off the getMovies function here…
export const getMovies = async () => {
const res = await axios.get('http://localhost:3000/api/movies')
return res.data
And the API endpoint it hits looks like this…
import firebase from '../../lib/firebase';
export default async(req, res) => {
const moviesRef = firebase
.collection('movies');
const snapshot = await moviesRef.get();
const movies = [];
snapshot.forEach(doc => {
movies.push({ id: doc.id, ...doc.data() })
})
res.json(movies)
Thanks in advance!
you should use your server link, not localhost.
You shouldn't hardcode http://localhost:3000 in the request's URL. You should omit it altogether since you're using Next.js API routes (same-origin).
export const getMovies = async () => {
const res = await axios.get('/api/movies')
return res.data
}
Edit: The above solution would work with API routes if the request was happening on the client-side only.
Since the request is made in getInitialProps, you should simply move the logic in your API route to a separate function (could very well be getMovies in this case) and call that directly in getInitialProps instead.
export const getMovies = async () => {
const moviesRef = firebase.collection('movies');
const snapshot = await moviesRef.get();
const movies = [];
snapshot.forEach(doc => {
movies.push({ id: doc.id, ...doc.data() })
});
return movies;
}

React Router: Update only one query parameter instead of replacing all

I am trying to update only one query param key-value on button click using react-router (v5).
const btnClickHandler = () =>{
history.push({ search: 'popup=false' });
}
I want this code to update the url from:
https://base-url.com/?popup=true&checked=true
to:
https://base-url.com/?popup=false&checked=true
but instead, it replaces the whole search to:
https://base-url.com/?popup=false
Basically, instead of replacing all the query param key value, how can I replace only one?
With the version 6 of react-router-dom, you could:
const [searchParams, setSearchParams] = useSearchParams();
let updatedSearchParams = new URLSearchParams(searchParams.toString());
updatedSearchParams.set('operation', 'edit');
setSearchParams(updatedSearchParams.toString());
You need to merge the query params yourself before updating them. You could use query-string (https://www.npmjs.com/package/query-string) library to make your job easier.
import qs from 'query-string';
const Component = ({ location}) => {
const btnClickHandler = () =>{
const queryParams = qs.parse(location.search);
const newQueries = { ...queryParams, popup:false};
history.push({ search: qa.stringify(newQueries) });
}
}

Categories