Im new to NextJs and im trying to pass an object to another page through a component. I'll post the code and explain better what im trying to do:
The object is like this:
objectEx = {
name: 'name',
description: 'description'
}
This is the main component:
Im trying to pass the object in the Router.push
export default class ComponentDummy extends Component {
handleSubmit = value => e => {
e.preventDefault()
Router.push({
pathname: '/OtherPage'
query: { **PASS AN OBJECT HERE** } //what im trying is: query: { objectEx: objectEx},
}
}
}
This is the page that im trying to receive the object in query
const OtherPage = ({ query }) => {
return(
<div>
Do Stuff with the object here
</div>
)
}
OtherPage.getInitialProps = ({ query }) => {
return { query }
}
Then on the page above im trying to access the object like:
query.objectEx.name
This is not working as I thought I would. How can I achieve that?
Thanks in advance
Well, first thing is you passed object as a query param.
Router.push({
pathname: '/OtherPage'
query: { data: objectEx}
}
So, in order to access the object in the OtherPage, you need to fetch this inside componentDidMount.
componentDidMount() {
let data = window.location.search;
console.log(data)
}
You are not allowed to pass Object as query param for next/router. You need to pass string
Router.push({
pathname: '/OtherPage'
query: { objectEx: JSON.stringify(objectEx) },
}
Keep in mind, that you'll need to parse it your self
const params = JSON.parse(decodeURIComponent(router.query.objectEx))
Better yet to use lib like qs for stringifying objects to URL params.
Related
I will make it simple:
Link: http://localhost:3000/product/bioCloths?activeCategory=medium&id=0
File path: pages/product/[product].js.
Expected: product: "bioCloths, activeCategory: "medium", id: "0"
using getStaticProps at [product].js:
const ProductDetails = (props) => {
console.log("initial props", props);
return <div>product details...</div>
};
export default ProductDetails;
export async function getStaticProps(context) {
return {
props: {
context: context
},
};
}
export async function getStaticPaths() {
return {
paths: [{ params: { product: "1" } }, { params: { product: "2" } }],
fallback: true,
};
}
Props returns: context: params: product: "bioCloths", excluding the query params.
Now if I use the deprecated getInitialProps instead:
ProductDetails.getInitialProps = (context) => {
const activeCategory = context.query.activeCategory;
const id = context.query.id;
const product = context.query.product;
return {
activeCategory: activeCategory,
id: id,
product: product,
};
};
props logs activeCategory: "medium" id: "0" product: "bioCloths"
I need to get these all of these props so I can fetch data before the client mounts.
I understand that getInitialProps is now deprecated, but it works. Why is not getStaticProps working, and should I use it instead of serverSideProps?
This is an ecommerce, and there is no way I can set getStaticPaths for hundreds of possibilities, to work along with getStaticProps so I guess that in this case I should use getInitialProps or getServerSideProps?
P.S - getServerSideProps hits me an error stating that it will only accept .json files.
According to one of the maintainers of Nextjs this is the reply for anyone learning this framework:
getStaticProps generates the page at build time. There's no possible way to know the custom query params your visitors can use at build time.
getInitialProps and getServerSideProps can know all the possible query params because the page is generated at runtime, whenever you receive a new request.
You can learn more about the above here.
"
This discussion can be read on Github
If your page uses a dynamic route, params contain the route parameters. For instance, If the page name is [id].js, then params will look as follows:
{ id: /* something */ }
You can get URL params from inside your getStaticProps or getServerSideProps function with the context argument.
Here’s an example with getStaticProps:
// pages/[id].js
export async function getStaticProps(context) {
const { params } = context;
const id = params.id;
const data = /* Fetching data with the id */
return {
props: data,
}
}
You can do the same with getServerSideProps:
// pages/[id].js
export async function getServerSideProps(context) {
const { params } = context;
const id = params.id;
/* ... */
}
New to Angular/Apollo/TS and this is driving me nuts, so any help is appreciated.
I am working on setting up a small app with Angular 10, Apollo, and a GraphQL API. I recently built the same thing in Vue and thought recreating the project would be a good way to pick up some Angular.
My connection to the API is working, as is my query, but I can't figure out how to map the results to an array so I can access them in my component. Using console.log inside the subscription shows the correct data is returned. console.log outside of the query on 'this' shows the query results, however they are never saved/mapped to the variable they should be set to.
Here's the code for my service:
import { Injectable } from '#angular/core';
import { Apollo } from 'apollo-angular';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import gql from 'graphql-tag';
const USER_SEARCH = gql`
query getUsers {
search(query: "moose", type: USER, first: 10) {
nodes {
... on User {
login
email
location
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
userCount
}
}`;
export class UserService {
loading: boolean = true;
users: [];
constructor(private apollo: Apollo) { }
getUsers(): any {
this.apollo.watchQuery<any>({
query: USER_SEARCH
})
.valueChanges
.subscribe(({ data, loading }) => {
this.loading = loading;
this.users = data.search;
});
console.log(this);
return this.users;
}
}
I can call the getUsers() function from my component, and 'this' has the service listed, and inside of it 'users' has my query results listed in it. However, console.log for this.users in the service or the component returns undefined.
I've tried about every type of example I could find, including the query examples from the apollo docs, and the example of using apollo with angular from hasura.io. Tried using a pipe and map, pluck, just valueChanges, a few different subscribes, setting a variable inside the function to assign the data value to, setting the query to variable, setting the query in ngOnInit in the component, and a few other things I'm sure I'm forgetting. Nothing seems to work. I looked into using a callback to wait for the query to return before setting the value, but my understanding is that I shouldn't have to do anything like that. I'm sure it's something dumb I'm missing or don't know about with Apollo or Angular, but I'm just not positive what it is I'm missing.
Any ideas?
this.getUsers = this.getUsers.bind(this);
within a constructor?
using setTimeout is not an ideal solution, you can directly update your component variable in subscribe callback function and do whatever you want to do with it in your template. Look at my example
getItems() {
this.apollo
.watchQuery({
query: this.getItemsQuery,
})
.valueChanges.subscribe((result: any) => {
this.items = result?.data?.items;
});
}
and in template
<mat-option *ngFor="let item of items" [value]="item.price">
{{ item.name }}
</mat-option>
Maybe not the ideal solution, so I'm still open to trying other things, but I was able to get the value set in my component by using a promise with a timer in the service, then an async await in the component.
Service
getUsers(): any {
return new Promise((resolve, reject) => {
let me = this;
this.apollo.watchQuery<any>({
query: USER_SEARCH
})
.valueChanges
.subscribe(({ data, loading }) => {
this.loading = loading;
this.users = data.search;
});
setTimeout( function() {
if(me.users !== 'undefined'){
resolve(me.users)
}
}, 1000)
})
}
Component
async getUsers(): Promise<any> {
this.users = await this.userService.getUsers();
console.log(this.users);
}
This allows this.users to be set from the service. As far as I can tell, Apollo is still running the query when Angular starts setting values, resulting in the value originally being shown as undefined, but my service having values from the query in the console. Not sure if there's a better way with Apollo or Angular to resolve this issue, but if so I'd love to hear about it.
Thanks!
I'm a bit new at frontend, so I have a question about code practices with with props importing.
I'm using next.js (which is based on React) and I'm need to insert props from API endpoint right to my page.
According to the example, it should looks like this:
export async function getServerSideProps({query}) {
const res = await fetch(encodeURI(`url_here+${query}`));
const json = await res.json();
The problem is with «what happens» next:
If I export my props (result of the function above) to page like this:
return { props: {
_id: json._id,
ilvl: json.ilvl,
...
checksum: json.checksum,
And import it like with using of destructuring assignment as an argument function:
function CharacterPage({ _id, id, ... }) {
...
}
THE PROBLEM
That there are almost 16+ key:values in response json object from API endpoint.
So if I will follow to the codestyle from above that will be.. em.. guess you already understand.
So I could export result from API endpoint like:
export async function getServerSideProps({query}) {
const res = await fetch(encodeURI(`url_here`));
const json = await res.json();
return {props: {json}
}
And import it, as one argument to the page like:
function CharacterPage({json})
But if I'll use json.name object keys on page (for conditional rendering) my IDE (WebStrom) shows me unresolved variable warning.
So where can I read about correct import practice and find react-import props example with lots of keys from JSON?
Should I use:
let {id, name, ...etc} = json
right after:
function CharacterPage({json})
for every key that I want to access or there is a better way/code practice for importing props?
My First idea is you can modify the JSON object in return of getServerSideProps. It would be more clear to identify which kind of object with attributes used here.
return { props: {
name: json.name,
id: json.id
...
}
}
If you cannot do that, it would be better to destructure initially.
let {id, name, ...etc} = json
But only destructure the elements you need. There is no need for destructuring all the elements.
With redux, when the state changes it updates any components props that is connected to the store with mapStateToProps. However with Apollo when performing a mutation, any component that is using the same data receive the new props.
I understand this is expected behaviour because Apollo doesn't know that the data sets are the same. Here's an example of what I'm getting at:
const query = gql`query { me { username } }`
#graphql(query)
class Header extends React.Component {
render () {
return <h1>{this.props.data.me.username}</h1>
}
}
const mutation = gql`mutation updateAccount($username: String!) {
updateAccount(username: $username) {
me {
username
}
}
}`
#graphql(mutation)
class Edit extends React.Component {
render () {
# ...
}
onSubmit(e) {
e.preventDefault()
this.props.mutate({variables: {username: this.state.username})
}
}
The Header component renders out the username, where as the Edit component updates the username. I want to re-render Header when username changes. I'm not sure how to do this without polling the query.
Apollo keeps an internal cache of queries and is able to normalize the result sets with dataIdFromObject using the internal cache kept in the redux store.
In order to use the internal cache you must set dataIdFromObject when initializing your client:
const client = new ApolloClient({
dataIdFromObject: o => o.id
})
Then when performing a mutation, ensure the id is returned in the return type:
const mutation = gql`mutation updateAccount($username: String!) {
updateAccount(username: $username) {
me {
id
username
}
}
}`
The query should also contain the id:
const query = gql`query { me { id username } }`
Apollo will recognise that the id is identical between the query and the return type of the mutation and update the query data accordingly.
I'm using Global ID's in my GraphQL API so the id is always unique across types but if you are using auto-increment ids or they are not unique then you can use __typename from the object:
const client = new ApolloClient({
dataIdFromObject: o => `${o.__typename}:${o.id},`
})
I need a resource that wouldn't be a collection but single item instead. I don't see anything about customizing mongoose service in that way.
You can return anything from your find method, it does not have to be a collection. So to get an object for e.g. /singleton you can just do something like:
app.use('/singleton', {
find: function(params) {
return Promise.resolve({
test: 'data'
});
}
});
This will of course also work via a websocket socket.emit('singleton::find'). For the Mongoose service there are two options:
1) Extending
Extend the service and then call it with a single object like this:
const MongooseService = require('feathers-mongoose').Service;
class SingletonService extends MongooseService {
find(params) {
return super.find(params).then(data => data[0]);
}
}
app.use('/singleton', new SingletonService({
Model: Todo,
name: 'todo'
}));
2) Hooks
Potentially even nicer with feathers-hooks, register an after hook that retrieves the singleton item from the collection originally requested:
const hooks = require('feathers-hooks');
app.configure(hooks())
.use('/singleton', mongooseService('todo', Todo));
app.service('singleton').hooks({
after: {
find(hook) {
const firstItem = hook.result[0];
hook.result = firstItem;
}
}
});