How do I route with query string params in Next.js? - javascript

I have a URL like
bar?id=foo
If I route to this via router.push('bar?id=foo') everything works fine.
But if I go direct to the route in the browser, the query string does not get passed through.
const BarComponent = ()=>{
console.log(useRouter())
}
This outputs
ServerRouter {
route: '/bar',
pathname: '/bar',
query: {},
asPath: '/bar',
basePath: '',
events: undefined,
isFallback: false,
locale: undefined,
isReady: false,
locales: undefined,
defaultLocale: undefined,
domainLocales: undefined,
isPreview: false,
isLocaleDomain: false
}

That's the output you get on the terminal from the server, and shows its default value ({}). On the client, you should see 2 console logs: first one with an empty query object (from SSR) and a second one with your query string in it (from rehydration).
useRouter() is a React Hook so it'll only run/update on the client.
If you want to have access to the query string on the server-side, you'll need to use getServerSideProps and access it through the query param from the context object.
export async function getServerSideProps({ query }) {
console.log(query) // `{ id: 'foo' }`
//...
}

Related

How is $route object initialized?

I tried to access this.$route on created() hook, but as I log it to the console it always returns an empty object
{path: '/', name: undefined, params: {…}, query: {…}, hash: '', …}
fullPath: "/"
hash: ""
matched: []
meta: {}
name: undefined
params: {}
path: "/"
query: {}
redirectedFrom: undefined
[[Prototype]]: Object
I guess it is because the loading is asynchronous? Then how can it locate the path from the beginning ??
I tried to do this and it worked. I wonder if anybody could explain what happens under the hood.
localhost:8080/?server=BlackHole
// index.js
{
path: '/network-error',
name: 'NetworkError',
component: NetworkError
},
{
path: '/:server',
},
// App.vue
created() {
setTimeout(() => {
// △ Request to unreachable server
if (this.$route.query.server == 'BlackHole')
{this.$router.push({ name: 'NetworkError' })}}, 1)},
Thanks in advance :)
When you'r on the /network-error route, the app is above that, so you can't say in the app where are you in my app ?
Because your application at this time created and mounted the view app and after go inside the route detected.
The good and normal practice is to fetch every route before like a middleware, inside your router.js or routes/index.js use this function:
router.beforeEach(async (to, from, next) => {
if (to.name === 'BlackHole') {
next({ name: 'NetworkError' })
}
next()
})
This maybe doesn't not exactly match your redirect because i miss some information, but i think you understand what you have to do.
The problem was because the route load is an async process, I found a very quick solution here, just add this line of config to main.js:
router.isReady().then(() => {app.mount('#app')})
https://www.youtube.com/watch?v=a6gT6qHtch8&ab_channel=VueMastery

Why passing data through Vue-router returning "[object Object]"?

What I'm trying to do is to pass some data from one component to another via router (I'm using Vue-Router-4 with Vue 3.0). But the data that I'm getting back is just "[object Object]" instead of the actual value. Here is what I did. Inside the component that sends the data I have this function
goToQuestions() {
this.$router.push({
name: "QuestionsPage",
params: {
data: this.questions
},
});
},
inside my index.js I have this
{
path: "/questions-page",
name: "QuestionsPage",
props: true,
component: () =>
import ('#/views/QuestionsPage.vue')
},
And then inside the receiver component I have this snippet
props: ["data"],
mounted() {
console.log("data coming from the router", this.data);
},
I am assuming you this.questions is either array or object.
with router it is advised not to send objects and arrays. Instead send an id .
And on the receiver page use that id to fetch the data.
Even if you want to pass object you can try this:
when adding routes, use props's Function mode so that it has a default property user and it will add route.params as props.
{
path: '/questions',
name: 'questions',
component: QuestionsComponent,
props: (route) => ({
user: userData,
...route.params
})
}
use this to push into your route
self.$router.push({
name: 'questions',
params: {
data: this.questions
}
})

Send an enum to graphql API from react app

I have an input (attached image) that I need to send to the graphql api from react application.
I am using below code to send this object and enum with init to graphql api
Reactjs Code
const RequestActionEnum = {
NEW: 'New',
UPDATE: 'Update',
ARCHIVE: 'Archive'
}
LocalCodeMutation({
variables: {
data: {
id: null,
city: values.jurisdiction,
country: values.country,
description: values.description,
edition: values.edition,
name: values.codeName,
note: 'test',
requestType: RequestActionEnum.NEW, // this is where i am sending enum value to api
state: values.state
}
}
});
Below code is where I am calling the mutation
const [LocalCodeMutation] = useMutation(LOCALCODE_MUTATION, {
refetchQueries: () => [
{ query: GET_LOCALCODES },
],
});
export const LOCALCODE_MUTATION = gql`
mutation LocalCodeMutation($data: LocalCodeRequestParamsInput) {
localCodeMutation(data: $data) {
ok
errors
localCodeInsertedId
}
}
`;
I am getting this error when I send to the API:
Error: GraphQL error: Variable $data got invalid value.
How can I send enum value to graphQL api from react component.
Could any one please suggest any ideas on this?
The enum values for RequestActionEnum are
NEW
UPDATE
ARCHIVE
If you were using this enum as a literal (not a variable), you would write it like this:
{
someField(someArgument: NEW)
}
Similarly, if you're using variables, you would use "NEW". Instead, you're using "New", which is not a valid enum value for this particular enum.
FWIW, if you actually read through to the end of the error, it would tell you as much as well.

How to pass array of objects to the graphql query from js client

I want pass to server array of object throw graphql API.
my query on the schema:
export const schema = buildSchema(`
type Query {
statistics(
modelId: String
picksEnds: [PickEnd]
)
}: Statistics
type PickEnd {
end: String
limit: float
}
...
`)
my js based query on clients side:
const createStatisticsQuery = (...) => {
return `query {
statistics(
modelId: "${modelId}",
picksEnds: ${JSON.stringify(myEnds)}
) ...
but get error from graphql:
message: "Syntax Error: Expected Name, found String "end""
snippet from request payload:
{"query":"query {\n statistics(\n modelId:
\"5ca0f4afb88b3a2e006faa0d\",\n
picksEnds:
[{\"end\":\"home\"},{\"end\":\"draw\"},{\"end\":\"away\"},{\"end\":\"under\",\"limit\":0.5},{\"end\":\"over\",\"limit\":0.5},{\"end\":\"under\",\"limit\":1.5 ...
While GraphQL syntax is similar to JSON, you cannot use JSON inside a GraphQL document, which is what you're doing by calling JSON.stringify and then inserting the result into your template string.
What GraphQL expects:
[{end:"foo",limit:2.0}]
What using stringify does:
[{"end":"foo","limit":2.0}]
Since this syntax is not valid, an error is thrown. The easiest way to get around this issue is to utilize variables to provide the needed input, since variable values are provided as JSON.
# Note: Replace PickEndInput with whatever your input type is actually called
query StatsQuery($id: String!, $ends: [PickEndInput!]!) {
statistics(modelId: $id, picksEnds: $ends) {
# ...
}
}
You can then construct a JavaScript object for the variables and pass it along to fetch, axios or whatever you're using to make your request. For example:
const variables = {
id: 'SOME_ID',
ends: [
{
end:'foo',
limit: 2.0,
},
],
}
const query = ...
fetch('SOME_ENDPOINT_URL', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ variables, query }),
})
Ideally, you'd want to use an existing client like Apollo to make these calls easier.

Vue, is there a way to pass data between routes without URL params?

I am looking how to pass data secretly between two separate components (not parent and child) without using URL params in my Vue2 app. This doesn't mean I am passing secrets but rather I just dont want the user to see it (only for UI considerations).
I know Vue has Props but they are meant for passing data between parent and child component.
In my case, my URL will change but I don't want to pass data via visible params.
Someone claimed to use props without URL params here but I haven't been able to reproduce a working solution (getting undefined each time).
I also checked out these options but they are all using either URL or query params which as we know are visible.
An ugly solution would be to write the data to local storage and then read it there but this creates a lot of overhead and complexity (like what if I only want this data to be read once, etc).
Is there a more elegant solution to this problem?
Thanks!
make props: true for the destination route -- in the index.js file of router
{
path: '/home',
name: 'home',
component: taskChooser,
props: true,
}
define prop in the component e.g props: ['myprop'], - note the quotes
copy the variable you want to pass from the source route into the same name as your prop - in this case myprop
myprop = theVariableThatYouWantToPass
this.$router.replace({name:'home', params:{myprop}});
Make sure that the name of prop and variable are same - the prop is in quotes.
It's working for me.
Thanks #Mayank for pointing me in the correct direction.
Here is the correct syntax that worked for me.
Notice the props in In router index
{
path: '/componentPath',
name: 'componentName',
props: {
header: true,
content: true
},
}
In the component you are redirecting to, define the props as following:
props: {
myProperty: {
type: <DATATYPE>
},
}
Perform redirect as following:
this.$router.push({
name: 'componentName',
params: {
myProperty: <VARIABLE>
}
})
Access props with the this. convention from created or in later lifecycle event.
In this case, the variable name and property name do not have to be the same as it is a simple map. That naming convention would be a curious design choice anyway.
I haven't tested this in Vue 2, but in Vue 3, you can pass a stringified object through the props when you click on a link:
Add props: true to your routes file, for the route.
{
path: 'receipt',
name: 'receipt',
component: () => import('../pages/Receipt.vue'),
props: true,
beforeEnter(to, from, next) {
if (!to.params.receiptData) {
return next({
name: 'dashboard',
params: {
locale: from.params.locale ? from.params.locale : 'en',
},
});
}
return next();
},
},
Include your stringified object as a param for router.push().
const receiptData = {
transferType: 'default',
recipient: receiver.value.name,
referenceNumber: '#B3423424234',
amountSent: formAmount,
transferFee: 0,
};
router.push({
name: 'receipt',
params: {
receiptData: JSON.stringify(receiptData),
},
});
Declare the props as instance data in the component.
<script setup>
import { computed } from 'vue';
const props = defineProps({
receiptData: {
type: String,
required: true,
},
})
console.log('receiptData', props.receiptData);
const parsedReceiptData = computed(() => JSON.parse(props.receiptData));
</script>
I haven't tested an upper limit for size, so be careful about passing a huge object through, and you'll notice I showed a beforeEnter middleware on the route too because, if the user presses F5 to refresh the page, the props will be lost, so in my case, I redirect the user away from the page because the receipt is for one time use only.

Categories

Resources