React + GraphQL = ❤

This is the👌 third article from the series “Build a Pokédex with GraphQL, React.js, Semaphore CI, Heroku and Docker”.

A quick recap from our previous chapters:

  • we built a GraphQL Server
  • we fetched data from PokéApi
  • we defined schemas
  • we interacted via GraphiQL
  • we wrote unit tests
  • we wrote integration tests

If you haven’t read the previous chapter I will put the link below, so you can give it a look 👀.

Webpack

We use Webpack as build tool. Its main goal is to group all our client’s application files to process and produce a build file. Webpack allows us to easily managing our assets, (optimization of images, css file concatenation, minification…).

Install Webpack:

npm i --save-dev webpack

We use Webpack version 2 which brings variety of anticipated features, including native support for ES6 modules. Using of imports and exports makes possible tree-shaking optimization. “Tree-shaking is the ability to only include code in your bundle that is being used.

“If you wonder why it’s called tree-shaking: think of your application as a dependency graph, this is a tree, and each export is a branch. So if you shake the tree, the dead branches will fall.” — Roman Liutikov

Learn more, with this article .

Here the webpack.config.js

We define an entry and an output file, the bundle is required by the index.html.

babel-loader is a Webpack loader, it parses all js and jsx files with babel. We configure babel with babelrc file.

Create a .babelrc in project’s root.

touch .babelrc

We configure babel to transpile jsx to js, and using last es2015 features !

Then install all babel dependencies:

npm i babel-core babel-loader babel-preset-es2015-native-modules babel-register --save-dev
  • babel-core : Babel itself
  • babel-loader : This package allows transpiling JavaScript files using Babel and Webpack.
  • babel-preset-es2015-native-modules : Babel preset for all es2015 plugins except babel-plugin-transform-es2015-modules-commonjs

It remains some Webpack configuration, but we have to add some code.

React Part

Create an app folder and the react root file app.jsx.

mkdir app && cd app
touch app.jsx

Install React and React-dom:

npm i --save-dev react react-dom

React-dom package makes a React element into the DOM in the supplied container. Here the container is a DOM element with the ‘app’ id.

Create an index.html with an app id. The template require the bundle.js generated by Webpack.

cd app
touch index.html

Copy-paste this content:

That index.html file should be moved in dist folder. We can use a plugin to copy this file to the dist folder. But we can be clever here. Thanks to the plugin html-webpack-plugin, the index.html should be moved in dist folder and the script automatically required, then we can pass an hash options to enable cache busting ! That plugin adds a query parameter to the dist file name, it’s different for each builds, thus browser see that the bundle has change.

Install html-webpack-plugin:

npm i --save-dev html-webpack-plugin

Then add a plugins property to Webpack’s configuration with that code:

Don’t forget to require html-webpack-plugin. Now we can remove the require for the bundle.js, it’s useless now.

Pokedex.jsx is the main entrypoint of our React App, let’s create a first version.

mkdir app/components && cd app/components
touch Pokedex.jsx

Now we have to start Webpack and the node server.

If you run npm run watch, the server will not be launched. This is because Webpack is in watch mode. The solution that I found it’s to run concurrently both commands, thus, each command can be launched. I’ve found concurrently module. If you have a better solution, please tell me in comments.

Install concurrently:

npm i --save concurrently

Here the final package.json

The last step is to create a middleware in index.js to serve our static resources.

app.use(express.static('dist'));

Now run

npm run watch

And browse http://localhost:3001 ! You should see a beautiful Hello World !

The Webpack part is over, we can start to code !

React component

Pokedex.jsx has responsibility to fetch Pokémons and manage actions happening from arrows.

Create 3 void methods forming your skeleton of Pokedex.jsx:

  • makeRequest : Take a Pokémon id and call the GraphQL server
  • arrowRight : Call makeRequest with an incremented id
  • arrowLeft : Call makeRequest with a decremented id

Create two buttons which bind arrowRight and arrowLeft. Implement each method.

Here a solution :

We bind this on arrowRight and arrowLeft methods into constructor because they are used in render. To keep the current index, we save it in state.

This code closes of the final solution. We have to update makeRequest to fetch Pokémon and finally add some static components.

Communicate with you GraphQL API

Create a client folder and a getPokemon.js file.

cd app
mkdir client && cd client
touch getPokemon.js

In this file we call our GraphQL server to fetch a Pokémon, it sends that request to grab a Pokemon :

We create a getPokemon method taking Pokémon id, building the url, and return the request.

I’ve choose superagent because it’s isomorphic, light and easy ! Now we can update Pokedex.jsx.

We have only one function so I’ve used export default.

If you click on the right button you should receive a object, with a body property containing :

Hourra ! 🎉🎉

React Components

The heart is now over, but it’s still very ugly.

Download this image and save it in a img folder. Rename that image in Pokedex.png.

The main screen display the Pokémon sprite, the second its name and in right bottom corner its id. We browse Pokémons with arrows left and right.

A concrete example :

There is not many css. So I decided to test style in component. I recommend you to see the presentation given by Christopher Chedeau, React: CSS in JS.

Radium is a set of tools to manage inline styles on React elements. It gives you powerful styling capabilities without CSS.
npm install --save radium

Radium support pseudo-class, media query, modifiers contrary to style inline. In addition CSS in JS gives us :

  • Scoped styles without selectors
  • Dead code elimination
  • Highly expressive

Set up Radium is not very hard, just export a Radium instance wrapping your class.

Write your style in an object, and access property in`style`tag. Example with the Pokédex image save previously:

Make img directory public:

app.use(express.static('img'));

We have 4 React components left. These components are stateless and functional. They are plain JavaScript functions with return containing the DOM element. Simpler than Class, there are no lifecycle methods, no state to manage or constructor. Functional components are greater performance, bigger testability and bigger readability than class. I encourage you to multiply stateless components and put logic in higher component.

Paddle : Left and Right buttons

Manage buttons.

cd app/components
touch Paddle.jsx

DetailInfo.jsx

Display the Pokémon order.

cd app/components
touch DetailInfo.jsx

ScreenInfo.jsx

Display the Pokémon name

cd app/components
touch ScreenInfo.jsx

Screen.jsx

Display the Pokémon sprite.

cd app/components
touch Screen.jsx

All components are writen, we have to compose them in the main class.

Pokédex.jsx

Conclusion

We have seen how making a front-end with React.js, using a build tool with Webpack and coupled with a GraphQL API. 🤙

I hope it wasn’t too hard, and I hope to see you on my next episodes ! The code is available on branch Chapter3 of Github.

Please tell me, if you see something to improve ! 🕵️