Creating an Isomorphic/Universal website with React — part 1

But after few seconds of excitement, the compulsive optimizer and performance nazi in you says: “Wordpress can be overkill for a personal portfolio…. Are you sure you want to have a database even if your website won’t be that dynamic?… Aren’t you afraid of possible vulnerabilities in the version of wordpress you’re using?”

So… that’s why you’re here…

Features

  • Isomorphism
  • Static build, plain HTML.
  • File based “database”
  • Fully featured, Url-friendly navigation
  • and much much

Tools Used

Golden rules of an Isomorphic Application

When you start creating an isomorphic application you should remember that:

  • window doesn’t exists on server-side so, don’t put it in your render() method, if you do you will see the typical
ReferenceError: window is not defined
  • ReactDOM.findDOMNode has to be used outside the render() method or react will trigger an error/warning. Don’t use it unless you need to obtain “data” from the real DOM node.
  • Think that the first rendering cycle will be on your server.

Let’s get Started

After installing gatsby and creating a new website (please refer at the official gatsby readme file) and adding few folders we will find ourselves with the following structure.

MichaelCereda.com
|- components / Our react components will sit here
|- css / Stylesheets, oh yeah
|- loaders / Gatsby loaders
|- pages / Website pages
|- assets / Static Assets
|- *.md / Bunch of Markdown pages ...
|- utils / various utilities
|- wrappers / Gatsby wrappers
gatsby develop

Website design

I decided to create a mono page website with the viewport split in two. When the user scrolls the webpage the left column will remain static while the left column will scroll.

props.route.pages:[
0:Object,1:Object,2:Object,3:Object,4:Object,
...
]

Refactoring Gatsby data Flow

So I added the following code in the index page

/pages/index.jsvar _ = require('lodash');export default class Index extends React.Component {
constructor(props){
super(props);
this.pageGroups = _.groupBy(props.route.pages, ‘file.dirname’);
this.pageGroups.root =
_.mapValues(_.groupBy(this.pageGroups[“”], “file.name”),
arr => arr[0]);

delete this.pageGroups[“”];
}
this.pageGroups: {
projects:[0:Object,1:Object,2:Object]
root:{
404:Object,
about_me:Object,
contact:Object,
index:Object,
intro:Object
}
}
let sitemap = [
{
section: ‘home’,
component: <MainSlider
{… this.state }
className=’color-one’
icon=’home’
{…this.pageGroups.root.intro.data}/>
},
{
section: ‘projects’,
component: <ProjectList
icon=’energy’
className=’color-two projects’
{… this.state }
projects={this.pageGroups.projects}
onProjectOpen={this.handleSectionOpen.bind(this)}/>
},
....
];

--

--

Code Ninja, Entrepreneur and Graphic Designer http://michaelcereda.com

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store