Gatsby createPage actions vs {page.slug}.js - reactjs

What is the main difference between creating static pages with createPage in Gatsby vs using {page.slug}.js. I was not able to find any documentation about this so I am not sure what to search for other than the documents encouraging the use of {page.slug}.js format.

Short answer: there's no difference at all between using gatsby-node.js and File System Route API ({page.slug}.js), they are different ways of achieving the same result: dynamic routes.
TL;DR
The File System Route API adds the simplicity that in most cases you lack using gatsby-node.js way of creating dynamic pages. For simple use-cases, I'd say that it's better to use the File System Route API but, because of some known limitations, for some complex scenarios, it's better to use gatsby-node.js (and maybe it's the only way).
The Filesystem Route API always filters by id as you can see in the docs:
allProduct {
nodes {
id # Gatsby always queries for id
fields {
sku
}
}
}
It may work in your scenario but if you need more complex filtering, the File System Route API may not be suitable.
For example, if you are writing a blog, you may think that the File System Route API works for you and it could be. But if at some point you want to filter the page creation some posts based on a complex and custom value (i.e: the typical isFuture field that checks if the date of the post is past or present and it's created customizing the GraphQL schema), you will find the "limitations" of the File System Route API.
In the end, it's all based on choosing what fill fit you better.
Summarizing (a lot)...
File System Route API
Simplicity: you get rid of gatsby-node.js and the code related
Limitations:
Always queries for the id
Can't pass custom properties to the view/template
Potential troubles by creating dynamic path segments based on a previously queried result
Path creation is a little bit complex for the same properties (i.e: slug): in this case, you will need to define a gatsbyPath for each property (docs)
gatsby-node.js
"Complexity": you always have a gatsby-node.js file with all the queries
Easy to manipulate the page creation (createPage) and to drill down any object or variable using the pageContext which gives you a lot of flexibility.
Path creation based on any desired value is easy to achieve.

Related

How does a GraphQL mutation know what node it's modifying? Is there a unique and global node ID for each node in the database?

I'm learning GraphQL through Robin Wieruch's helpful tutorial (https://www.robinwieruch.de/getting-started-github-graphql-api/)
One thing I'm unclear about is how a mutation for a particular endpoint "knows" what object it's modifying (queries seem to work by traversing the DB tree from top to bottom).
For instance, with the GitHub GraphQL API addReaction mutation (https://developer.github.com/v4/mutation/addreaction/), we have the subjectID, which the docs say is "The Node ID of the subject to modify.". OK, but presumably there might be more than one thing in the entirety of GitHub to which one might want to add a reaction. Does this mean that this subjectID is unique across the entirety of GitHub, so that the GraphQL API knows 'automagically' exactly where in all of the many elements in GitHub it should add (for example) a 'thumbs up'? If that's not the case, how does it know? If it is the case, does this unique and global ID exist permanently, up until the node is deleted?
GitHub's GraphQL schema is Relay-compliant. From their homepage:
Relay is a JavaScript framework for building data-driven React applications powered by GraphQL, designed from the ground up to be easy to use, extensible and, most of all, performant.
While Relay is a front-end client, it requires schemas to include certain features in order for the client to work as expected. One of these features is Global Object Identification. How you provide an id that's globally unique is left up to the server. However, Relay provides a server-side helper library that has a built-in mechanism:
export function toGlobalId(type: string, id: string): string {
return base64([type, id].join(':'));
}
export function fromGlobalId(globalId: string): ResolvedGlobalId {
const unbasedGlobalId = unbase64(globalId);
const delimiterPos = unbasedGlobalId.indexOf(':');
return {
type: unbasedGlobalId.substring(0, delimiterPos),
id: unbasedGlobalId.substring(delimiterPos + 1),
};
}
All this does is combine the id and the GraphQL type and then encodes it using Base64. As long as you're not returning rows from different tables as the the same type, this is guaranteed to be unique.
So that's how GitHub's API works. However, not all GraphQL APIs are Relay-compliant. There's both benefits and costs to designing a schema that way. To answer your question more directly, how a field is resolved is entirely up to the server. The resolver you write for a particular field (including root-level mutations) is passed in a couple of pieces of information:
the value the parent field resolved to
the arguments for the field
Most implementations also provide some kind of context object and an info object that describes the GraphQL request itself, although this is not strictly part of the spec. The point is, that's all the resolver is really "aware" of. However, since you're the one writing the resolver, you know what data needs to be queried or manipulated based on the field you're writing the resolver for.

Marionette Router Query String Parameters In URL Fragment Routes

I'm working on a project that requires that most UI state is reproducible via URL. In a traditional (server-side) app, I could use both URL parameters like:
/resources/:id
and unordered optional query string parameters, like:
/resources/:id?page=5&sort=date
Is there an idiomatic way to achieve this with Backbone/Marionette routing? I don't want to have to configure routes for every possible combination of parameters.
The fact that I don't see this addressed much makes me think I may be barking up the wrong tree, approach-wise, but I do think being able to represent as much UI state as possible in the URL is pretty important to a lot of projects.
It looks like the best option is the now-orphaned backbone-query-parameters project.
It supports routes exactly in the form I'm looking for:
#resources/:id?flag=true
URL parameters are not really enforced by Backbone/Marionette. One possible reason is that URL parameters are not SEO friendly.
Instead, you can configure optional URL fragments which will work pretty much like URL parameters, this way:
/resources/:id(/page/:page)(/sort/:sort)
If you do this way, the only gotcha here is that this sequence of "parameters" need to be ordered.
HOWEVER if you need it to be unordered, you can simply use Regular Expressions with router.route() method inside your initialize, as explained in Router#route

CakePHP - Best way to persist application state?

I have an app that tracks and displays various stats for a local athletic league. One of my requirements is to be able to break down stats by game type, league id and location id. The user picks a value for each of those 3 items and then goes off to view various stats with the 3 variables stored in a session. This works fine, but my problem is that users can't link back to whatever stats they were viewing. I know I can extend the life of the session, but I'd rather pass the state of those 3 variables around in the URL so I can have the ability to link back to any specific stats page with any or none of those 3 variables defined.
Query strings seem like an obvious way to do this, but I can't tell if there's any way for me to 'automatically' append the query string to all links generated in the app, or if I manually need to go through and add the querystring parameters wherever I generate a link or do a redirect. That seems like the brute force approach and I feel like there must be a better way to do this sort of persistence that I'm missing. Any help appreciated!
For a number of reasons (linking, SEO...etc), use a URL, not sessions/cookies. And instead of IDs, use slugs instead:
www.mysite.com/league/football/youth/newyork
I'm sure there are many different ways to keep the url vars consistent across the board, but the way I can think to do it would be the following:
You can use Cake's route functionality to set each item to a variable and make nice looking URLs
In your AppController's beforeFilter(), set the Session of each item (type, league, location)
Make a custom MyHtmlHelper
in it, check if your Session for each contains data, and if it does, append to every link that needs it (could use only for specific controllers, actions...etc)
I hope there's a simpler way, but that's all I could think of offhand.

React-router: Passing data through routes

I'm trying to figure out the best way to pass data through my routes. I know I can use params but there are certain types of data that don't belong in params.
For example: I have an index page that displays a list of applications. Each application has a button next to it which will route you to the view for that application.
I want to pass the application itself to the Application handler. However, it doesn't make sense to pass the entire application through params. Though it does make sense to pass the application identifier to params (i.e. :id or :name)
So the way I think I should be doing this is pass the application identifier to params, then in the Application component search my ApplicationStore for the appropriate application given the identifier.
Though, wouldn't it be easier and faster to pass the application itself? Is there a way to do this. Is there a reason not to do this?
Here is some code:
<Link to="showApplication" params={{name: application.name}}>View</Link>
or
<Link to="showApplication" params={{application: application}}>View</Link>
Thanks in advance!
The problem is that when the person refreshes, or in some other way directly loads the url, it needs to show the correct view. Because URLs are just strings, you need to represent the route as a string. You can't (easily) shove an actual application into the url.
The job of a router is to take that string (the URL) and map it to the actual code (the handler), and provide any extra data (the params, query, and/or hash).
Your job as a router user is to ensure there's enough information in the URL for the router to pick the right handler, and for the handler to have enough information to do its job (e.g. which application to show).
If the url is something like mysite.com/showApplication, there's clearly not enough information.
If it's something like:
mysite.com/showApplication/React.createClass(%7Brender%3A%20function()%7Breturn%20React.createElement('div'%2C%20null%2C%20%22I'm%20an%20application!%22%7D%7D)%3B
i.e. putting an application in the url, that's too much information, and generally a very bad idea.
But mysite.com/showApplication/applicationName is just right :-)
I'll provide an easy and hacky way, have a global object which you use to share information across routes eg.
window.CONTEXT = {'share':'this'}
Note that it's quite important only to use this way if the object you want to share can be recreated by the route itself, as FakeRain mentioned above the route has to contain just enough information for it to give the user the same experience if they reload.
The only reason you'd use this is to save bandwidth if you need to request information for what you want to share but yet you don't want a huge link.

In asp.net-mvc, how can I refactor my site.master page to support 2 different master views?

I have a team asp.net-mvc website and in the site.master page I have
a header image
a menu
all my js and css includes.
I now need to use the site for two different teams where I run the site on two different ports and each team only see's their team's info (pretty much same exact site and same db but just different database filters)
I achieved the backend by adding this to my controller class:
string team = ConfigurationManager.AppSettings["Team"]
and based on that value, it changes the DB queries i run. That is working great but now I need to do some tweaking on the frontend (as i realized the header image and some menu items need to change as well)
Given that, I now need to refactor the site.master as i need to use the same codebase to support the view for two different teams and I want
Each team to show its own headerImage
Each team to have its own menu items
Avoid duplicating any common code (like css an js includes)
(which are now just hardcoded in the site.master file)
I could copy and paste all of the code into a different master page (lets say site2.master) and duplicate all of the common code but I wanted to see if there was the ability to factor out all of the common code between the 2 master files to avoid duplication.
Also, i am trying to figure out how i can have my code dynamically "figure out" which master file to use based on a config entry. I was thinking about using nested master pages but that doesn't seem to work because each page really is applicable to both Team1 and Team2 and just needs to get set dynamically. I hopefully want to avoid a situation where I have this switch code on EVERY controller action
Since you will have different menu items (this is the major part of what you said that is determining my answer), I believe that two master views would be the better approach rather than having either:
a) a If/Else in your master view or
b) a ton of configuration entries that you would have to parse on each
request, and
c) Provides an easier path for more custom theme-ing in the future if
so requested or needed.
But, there are definitely ways to reduce the amount of code that you need to write and avoid duplication. Below are some suggestions that I would recommend
1.Use the same logic as you do with your DB query settings to set the master page depending on the team. Example:
<appSettings>
<add key="team" value = "WhateverYouAlreadyHave"/>
<add key="layout" value = "~/Views/Shared/team.master"/>
</appSettings>
2.In your views, specify your layout view in the top portion as so:
#{
ViewBag.Title = "My Page Title";
Layout = #ConfigurationManager.AppSettings("layout");
}
3.In your master views, factor our the JS and CSS into a shared partial view that you can call from the master pages
#{Html.RenderPartial("HeadContent");}
I believe that this achieves your goals of not repeating yourself in your layout information as well as cuts down the potential need of If/Else statements in your master views. Lastly, if you ever had to separate out the sites (different servers or something) you should be able to do that quickly without having dead code floating around your views.
Lastly, I suppose an alternative solution would be to keep a single layout file, but reverse what goes into the shared partial view. Meaning you could store the header image as a configuration value as well as the shared partial view name. In this instance, put your menus in their own partial view that you could call from a single master. However, if you really wanted to provide custom layout/look/theme in the future, this would be more problematic to achieve with a single master page.

Resources