Rendering basics
Contents
In this chapter we will look into the basic rendering mechanisms, and add some custom rendering to our app as well.
Dev mode rendering
As you have seen during the setup of Next, each content item automatically render a page, listing available props. These props are fetched by the Enonic Adapter.
By defining custom queries and react components tailored for each content type, we can customise the props passed to the view, and which template is actually applied.
Task: Get person content
Let’s build our first component - starting with rendring of "person" content types:
The full name of your content type should now be "com.example.myproject:person" If you used a different name when creating the Enonic app, update the .env file in your Next app to reflect this. |
-
Add query by creating the following file in your Next application
src/components/queries/getPerson.tsimport {APP_NAME_UNDERSCORED} from '../../_enonicAdapter/utils' const getPerson = ` query($path:ID!){ guillotine { get(key:$path) { displayName ... on ${APP_NAME_UNDERSCORED}_Person { data { bio dateofbirth photos { ... on media_Image { imageUrl: imageUrl(type: absolute, scale: "width(500)") attachments { name } } } } } parent { _path(type: siteRelative) } } } }`; export default getPerson;
This file defines a graphQL query 'getPerson' that will fetch data from the Enonic API.
You may validate the query by copying it to the GraphQL playground. Replace APP_NAME_UNDERSCORED
withcom_example_myproject
and set a query variable, try this for instance:{"path": "/hmdb/persons/brad-pitt"}`
-
Register the query by adding the following lines to the component mappings file:
Do not copy the …
- it is just there to illustrate there are other lines of code you should keep in the target file.src/components/_mappings.tsimport getPerson from './queries/getPerson'; ... ComponentRegistry.addContentType(`${APP_NAME}:person`, { query: getPerson, view: PropsView });
-
View the result
By visiting a person item - like
http://localhost:3000/persons/morgan-freeman
you should now see data props being listed in the view.
Task: Add custom person rendering
With fresh content available, it’s time to make things shine:
-
Add view by creating the following file in your Next application
src/components/views/Person.tsximport React from "react" import {FetchContentResult} from '../../_enonicAdapter/guillotine/fetchContent'; import {getUrl} from '../../_enonicAdapter/utils' const Person = (props: FetchContentResult) => { const {displayName, data, parent} = props.data?.get as any; const {bio, photos} = data; const {_path} = parent; return ( <> <div> <h2>{displayName}</h2> <p>{bio}</p> { photos.map((photo: any, i: number) => ( <img key={i} src={photo.imageUrl} title={ (photo.attachments || [])[0].name || displayName } width="500" /> )) } </div> <p><a href={getUrl(_path)}>Back to Persons</a></p> </> ) } export default Person;
This file defines a react view 'Person' that will use the props from the query to render the person.
-
Register Person view by adding the following import to the component mappings:
src/components/_mappings.tsimport Person from './views/Person';
And then update the component mapping you created earlier to use the new view:
src/components/_mappings.tsComponentRegistry.addContentType(`${APP_NAME}:person`, { query: getPerson, view: Person });
-
Check the result - The page should automatically reload once the changes have been saved
The content type mapping applies to every person
content item in the site, regardless of it’s location in the hierarchy. Try looking at some other persons, eg. http://localhost:3000/persons/uma-thurman
Task: Add custom header and footer
Adding some styles, a header and a footer will make the site more interesting visually. Next provides a handy solution to this problem.
The _app.tsx
file initializes the React pipeline, and by modifying it we can inject the same header and footer components to all pages generated by Next.
Sample header and footer views are already included in the starter under /src/components/views , so all we need to do is put them to work. |
Update src/pages/_app.tsx`
with the following changes:
-
Add these imports
import Header from "../components/views/Header"; import Footer from "../components/views/Footer";
-
And replace this line:
return <Component {...pageProps} />;
with this:
return ( <> <Header title="🔥 Next.XP" logoUrl={getUrl('images/xp-shield.svg')}/> <main style={{ margin: `0 auto`, maxWidth: 960, padding: `0 1rem`, }}> <Component {...pageProps} /> </main> <Footer/> </> );
Pay attention to the getUrl('') function. It ensures that links to assets and pages are working seamlessly in Next.js, as well as in Content Studio preview mode - as you will see later. |
Morgan Freeman’s page should now look like this
The common query
You may have noticed the Common
props appearing in the various prop views - these originate from the the following statement in the mappings:
... // Common query ComponentRegistry.setCommonQuery([commonQuery, commonVariables]); ...
The result of this query is available across all components on the page, and may be useful if you want to fetch data for the page itself, or to be used across multiple components. Feel free to adapt it to your requirements.
If you do not need any common props, remove it from the mappings to optimize performance. |
With the basic rendering completed, in the next chapter, well add preview support in Content Studio.