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

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) });
}
}

Related

Router replace function is not working with Reactjs

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
};

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>;
};

Problem assigning data from onSnapshot firestore to a Vue ref variable

Me and my friends are using Vue with firestore to create some functionality.
This is our first experience using either and we are having some trouble.
We are now trying to add a onSnapshot to a doc on firestore and assign said
data to a vue ref variable thus making it possible to use a watcher and respond to changes.
As can be seen in the image our doc contains 2 arrays which is the data we need to reach after a change has been observed by the onSnapshot. Our problem is that we dont know how to assign gameData to the appropriate data so that we can reach and use a watcher outside of the function.
Datastructure on firestore
export function realTimeGame(lobbyId) {
const gameCollection = firestore.collection('lobbies/' + lobbyId + '/game_data');
const gameData = ref([]);
const unsubscribe = gameCollection.doc('gameThings').onSnapshot(snapshot => {
// gameData.value = snapshot.map(document => ({ id: document.id, ...document.data() })) .map is not defined
gameData.value = snapshot; //this is essentially what we want to do
});
onUnmounted(unsubscribe)
return { gameData }
}
We found a solution:
export function realTimeGame(lobbyId) {
const gameData = ref();
const unsub = onSnapshot(doc(firestore,'lobbies/' + lobbyId + '/game_data/gameThings'),(doc) => {
gameData.value = { ...doc.data()}
})
onUnmounted(unsub)
return gameData
}

How to use synchronous and asynchronous functions inside onClick method in React

I have a react component with this state
const [name, setName] = useState('')
const [comment, setComment] = useState('')
const [notes, setNotes] = useState([])
this function handles the input elements to fill the order
const handleComments = () => {
setNotes([...notes, {
name,
comment
}])
setName('')
setComment('')
}
and this function sends the info to the server
const update = async () => {
const newNotes = notes.map(note => ({
name,
comment
}))
return updateNotesPromise(newNotes)
}
here I have a button that has to execute both functions
<Button onClick={} />
How can I create a function that is passed through the onClick method and executes handleComments in order to load the info on the DOM and then, once that info there, executes the update function and saves the order info into the DB ?
It looks like you're using functional components, so you can create a useEffect that makes an API put request whenever notes gets updated:
useEffect(()=> {
updateNotesPromise(notes);
},[notes])
I'm assuming updateNotesPromise is a function that makes your request call? It's also unclear why newNotes is being mapped from notes, or why update is async when it doesn't await anything. Your onClick would simply trigger handleNotes (I'm assuming that is your submit button).
Here's a way to handle the component updating and server communicating with error handling:
const onButtonClicked = useCallback(async (name, comment) => {
// cache the olds notes
const oldNotes = [...notes];
// the updated notes
const newNotes = [...notes, {
name,
comment
}];
// update the component and assume the DB save is successful
setNotes(newNotes);
try {
// update the data to DB
await updateNotesPromise(newNotes);
} catch(ex) {
// when something went wrong, roll back the notes to the previous state
setNotes(oldNotes);
}
}, [notes]);

Categories