React Toolsandskills2ndedition
React Toolsandskills2ndedition
Author: Manjunath M, Michael Wanyoike, Camilo Reyes, JavaScript Joe, Pavels Jelisejev, Wern Ancheta,
Nilson Jacques, Craig Buckler
Cover Design: Alex Walker
Notice of Rights
All rights reserved. No part of this book may be reproduced, stored in a retrieval system or
transmitted in any form or by any means, without the prior written permission of the publisher,
except in the case of brief quotations embodied in critical articles or reviews.
Notice of Liability
The author and publisher have made every effort to ensure the accuracy of the information
herein. However, the information contained in this book is sold without warranty, either express
or implied. Neither the authors and SitePoint Pty. Ltd., nor its dealers or distributors will be held
liable for any damages to be caused either directly or indirectly by the instructions contained in
this book, or by the software or hardware products described herein.
Trademark Notice
Rather than indicating every occurrence of a trademarked name as such, this book uses the
names only in an editorial fashion and to the benefit of the trademark owner with no intention of
infringement of the trademark.
Published by SitePoint Pty. Ltd.
About SitePoint
SitePoint specializes in publishing fun, practical, and easy-to-understand content for web
professionals. Visit sitepoint.com to access our blogs, books, newsletters, articles, and
community forums. You’ll find a stack of information on JavaScript, PHP, Ruby, mobile
development, design, and more.
Chapter
1
React Router v5:
The Complete
Guide
Manjunath M, Michael Wanyoike
React Router is the de facto standard routing library for React. When you need to navigate
through a React application with multiple views, you’ll need a router to manage the URLs. React
Router takes care of that, keeping your application UI and the URL in sync.
This tutorial introduces you to React Router v5 and a whole lot of things you can do with it.
Introduction
React is a popular library for creating single-page applications (SPAs) that are rendered on the
client side. An SPA might have multiple views (aka pages), and unlike conventional multi-page
apps, navigating through these views shouldn’t result in the entire page being reloaded. Instead,
we want the views to be rendered inline within the current page. The end user, who’s accustomed
to multi-page apps, expects the following features to be present in an SPA:
Each view should have a URL that uniquely specifies that view. This is so that the user can
bookmark the URL for reference at a later time. For example, www.example.com/products .
The browser’s back and forward button should work as expected.
Dynamically generated nested views should preferably have a URL of their own too—such as
example.com/products/shoes/101 , where 101 is the product ID.
Routing is the process of keeping the browser URL in sync with what’s being rendered on the
page. React Router lets you handle routing declaratively. The declarative routing approach allows
you to control the data flow in your application, by saying “the route should look like this”:
<Route path="/about">
<About />
</Route>
You can place your <Route> component anywhere you want your route to be rendered. Since
<Route> , <Link> and all the other React Router APIs that we’ll be dealing with are just
components, you can easily get up and running with routing in React.
All the concepts connected with building these routes will be discussed along the way.
The entire code for the project is available on this GitHub repo.
Node comes bundled with npm, a package manager for JavaScript, with which we’re going to
install some of the libraries we’ll be using. You can learn more about using npm here.
You can check that both are installed correctly by issuing the following commands from the
command line:
node -v
> 12.19.0
npm -v
> 6.14.8
With that done, let’s start off by creating a new React project with the Create React App tool. You
can either install this globally, or use npx , like so:
cd react-router-demo
The React Router library comprises three packages: react-router, react-router-dom, and react-
router-native. The core package for the router is react-router , whereas the other two are
environment specific. You should use react-router-dom if you’re building a website, and react-
router-native if you’re in a mobile app development environment using React Native.
Congratulations! You now have a working React app with React Router installed. You can view
the app running at http://localhost:3000/.
The first thing we’ll need to do is to wrap our <App> component in a <Router> component
(provided by React Router). Since we’re building a browser-based application, we can use two
types of router from the React Router API:
BrowserRouter
HashRouter
The primary difference between them is evident in the URLs they create:
// <BrowserRouter>
http://example.com/about
// <HashRouter>
http://example.com/#/about
The <BrowserRouter> is the more popular of the two because it uses the HTML5 History API to
keep your UI in sync with the URL, whereas the <HashRouter> uses the hash portion of the URL
( window.location.hash ). If you need to support legacy browsers that don’t support the History
API, you should use <HashRouter> . Otherwise <BrowserRouter> is the better choice for most use
cases. You can read more about the differences here.
So, let’s import the BrowserRouter component and wrap it around the App component:
// src/index.js
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
The above code creates a history instance for our entire <App> component. Let’s look at what
that means.
The history library lets you easily manage session history anywhere
JavaScript runs. A history object abstracts away the differences in various
environments and provides a minimal API that lets you manage the history
stack, navigate, and persist state between sessions. — React Training docs
Each <Router> component creates a history object that keeps track of the current location
( history.location ) and also the previous locations in a stack. When the current location
changes, the view is re-rendered and you get a sense of navigation. How does the current
location change? The history object has methods such as history.push and history.replace
to take care of that. The history.push method is invoked when you click on a <Link>
component, and history.replace is called when you use a <Redirect> . Other methods—such
as history.goBack and history.goForward —are used to navigate through the history stack by
going back or forward a page.
The <Route> component is the most important component in React Router. It renders some UI if
the current location matches the route’s path. Ideally, a <Route> component should have a prop
named path , and if the path name matches the current location, it gets rendered.
The <Link> component, on the other hand, is used to navigate between pages. It’s comparable
to the HTML anchor element. However, using anchor links would result in a full page refresh,
which we don’t want. So instead, we can use <Link> to navigate to a particular URL and have the
view re-rendered without a refresh.
Now we’ve covered everything you need to make our app work. Update src/App.js as follows:
{ /* Route components are rendered if the path prop matches the current URL */}
<Route path="/"><Home /></Route>
<Route path="/category"><Category /></Route>
<Route path="/products"><Products /></Route>
</div>
);
}
Here, we’ve declared the components for Home , Category and Products inside App.js .
Although this is okay for now, when a component starts to grow bigger, it’s better to have a
separate file for each component. As a rule of thumb, I usually create a new file for a component
if it occupies more than 10 lines of code. Starting from the second demo, I’ll be creating a
separate file for components that have grown too big to fit inside the App.js file.
Inside the App component, we’ve written the logic for routing. The <Route> ’s path is matched
with the current location and a component gets rendered. Previously, the component that should
be rendered was passed in as a second prop. However, recent versions of React Router have
introduced a new route rendering pattern, whereby the component(s) to be rendered are children
of the <Route> .
Here / matches both / and /category . Therefore, both the routes are matched and rendered.
How do we avoid that? You should pass the exact prop to the <Route> with path='/' :
If you want a route to be rendered only if the paths are exactly the same, you should use the
exact prop.
Nested Routing
To create nested routes, we need to have a better understanding of how <Route> works. Let’s
look at that now.
As you can read on the React Router docs, the recommended method of rendering something
with a <Route> is to use children elements, as shown above. There are, however, a few other
methods you can use to render something with a <Route> . These are provided mostly for
supporting apps that were built with earlier versions of the router before hooks were introduced:
component : when the URL is matched, the router creates a React element from the given
component using React.createElement .
render : handy for inline rendering. The render prop expects a function that returns an
element when the location matches the route’s path.
children : this is similar to render , in that it expects a function that returns a React
component. However, children gets rendered regardless of whether the path is matched
with the location or not.
The path prop is used to identify the portion of the URL that the router should match. It uses the
Path-to-RegExp library to turn a path string into a regular expression. It will then be matched
against the current location.
If the router’s path and the location are successfully matched, an object is created which is called
a match object. The match object contains more information about the URL and the path. This
information is accessible through its properties, listed below:
match.url : a string that returns the matched portion of the URL. This is particularly useful for
building nested <Link> components.
match.path : a string that returns the route’s path string—that is, <Route path=""> . We’ll be
using this to build nested <Route> components.
match.isExact : a Boolean that returns true if the match was exact (without any trailing
characters).
match.params : an object containing key/value pairs from the URL parsed by the Path-to-
RegExp package.
Note that when using the component prop to render a route, the match , location and history
route props are implicitly passed to the component. When using the newer route rendering
pattern, this is not the case.
return (
<div>
<h2>Home</h2>
</div>
);
};
{
history: { ... }
location: { ... }
match: { ... }
}
{}
This might seem disadvantageous at first, but worry not! React v5.1 introduced several hooks to
help you access what you need, where you need it. These hooks give us new ways to manage our
router’s state and go quite some way to tidying up our components.
I’ll be using some of these hooks throughout this tutorial, but if you’d like a more in-depth look,
check out the React Router v5.1 release announcement. Please also note that hooks were
introduced in version 16.8 of React, so you’ll need to be on at least that version to use them.
The Switch Component
Before we head to the demo code, I want to introduce you to the Switch component. When
multiple <Route> s are used together, all the routes that match are rendered inclusively. Consider
this code from demo 1. I’ve added a new route to demonstrate why <Switch> is useful:
If the URL is /products , all the routes that match the location /products are rendered. So, the
<Route> with path /:id gets rendered along with the <Products> component. This is by
design. However, if this is not the behavior you’re expecting, you should add the <Switch>
component to your routes. With <Switch> , only the first child <Route> that matches the
location gets rendered:
<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/category"><Category /></Route>
<Route path="/products"><Products /></Route>
<Route path="/:id">
<p>This text will render for any route other than those defined above</p>
</Route>
</Switch>
The :id part of path is used for dynamic routing. It will match anything after the slash and
make this value available in the component. We’ll see an example of this at work in the next
section.
Now that we know all about the <Route> and <Switch> components, let’s add nested routes to
our demo.
Earlier on, we created routes for / , /category and /products . But what if we wanted a URL in
the form of /category/shoes ?
<Switch>
<Route path="/"><Home /></Route>
<Route path="/category"><Category /></Route>
<Route path="/products"><Products /></Route>
</Switch>
</div>
);
}
You’ll notice that we’ve moved Category into its own component. This is where our nested
routes should go.
return (
<div>
<h3>{name}</h3>
</div>
);
}
return (
<div>
<ul>
<li>
<Link to={`${url}/shoes`}>Shoes</Link>
</li>
<li>
<Link to={`${url}/boots`}>Boots</Link>
</li>
<li>
<Link to={`${url}/footwear`}>Footwear</Link>
</li>
</ul>
<Route path={`${path}/:name`}>
<Item />
</Route>
</div>
);
};
Here, we’re using the useRouteMatch hook to gain access to the match object. As previously
mentioned, match.url will be used for building nested links and match.path for nested routes. If
you’re having trouble understanding the concept of match, console.log(useRouteMatch())
provides some useful information that might help to clarify it.
<Route path={`${path}/:name`}>
<Item />
</Route>
This is our first proper attempt at dynamic routing. Instead of hard-coding the routes, we’ve used
a variable within the path prop. :name is a path parameter and catches everything after
category/ until another forward slash is encountered. So, a path name like products/running-
shoes will create a params object as follows:
{
name: "running-shoes";
}
To access this value within the <Item> component, we’re using the useParams hook, which
returns an object of key/value pairs of URL parameters.
Try this out in your browser. The Category section should now have three sub-sections, each with
their own route.
Let’s complicate things a bit more, shall we? A real-world router will have to deal with data and
display it dynamically. Let’s assume we have some product data returned by an API in the
following format:
const productData = [
{
id: 1,
name: "NIKE Liteforce Blue Sneakers",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie.",
status: "Available",
},
{
id: 2,
name: "Stylised Flip Flops and Slippers",
description:
"Mauris finibus, massa eu tempor volutpat, magna dolor euismod dolor.",
status: "Out of Stock",
},
{
id: 3,
name: "ADIDAS Adispree Running Shoes",
description:
"Maecenas condimentum porttitor auctor. Maecenas viverra fringilla felis, eu pretium.",
status: "Available",
},
{
id: 4,
name: "ADIDAS Mid Sneakers",
description:
"Ut hendrerit venenatis lacus, vel lacinia ipsum fermentum vel. Cras.",
status: "Out of Stock",
},
];
Let’s also assume that we need to create routes for the following paths:
Create a new file src/Products.js and add the following (making sure to copy in the product
data from above):
return (
<div>
<div>
<div>
<h3>Products</h3>
<ul>{linkList}</ul>
</div>
</div>
<Route path={`${url}/:productId`}>
<Product data={productData} />
</Route>
<Route exact path={url}>
<p>Please select a product.</p>
</Route>
</div>
);
};
First, we use the useRouteMatch hook to grab the URL from the match object. Then we build a
list of <Links> components using the id property from each of our products, which we store in
a linkList variable.
The first route uses a variable in the path prop which corresponds to that of the product ID.
When it matches, we render out the <Product> component (which we’ll define in a minute),
passing it our product data:
<Route path={`${url}/:productId`}>
<Product data={productData} />
</Route>
The second route has an exact prop, so will only render when the URL is /products and nothing
is selected.
Now, here’s the code for the <Product> component. You’ll need to create this file at src/
Product.js :
if (product) {
productData = (
<div>
<h3> {product.name} </h3>
<p>{product.description}</p>
<hr />
<h4>{product.status}</h4>
</div>
);
} else {
productData = <h2> Sorry. Product doesn't exist </h2>;
}
return (
<div>
<div>{productData}</div>
</div>
);
};
The find method is used to search the array for an object with an ID property that equals
match.params.productId . If the product exists, the productData is displayed. If not, a “Product
doesn’t exist” message is rendered.
<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/category"><Category /></Route>
<Route path="/products"><Products /></Route>
</Switch>
</div>
);
}
Now when you visit the application in the browser and select “Products”, you’ll see a sub-menu
rendered, which in turn displays the product data.
Have a play around with the demo. Assure yourself that everything works and that you
understand what’s happening in the code.
Protecting Routes
A common requirement for many modern web apps is to ensure that only logged-in users can
access certain parts of the site. In this next section, we’ll look at how to implement a protected
route, so that if someone tries to access /admin , they’ll be required to log in.
However, there are a couple of aspects of React Router that we need to cover first.
As with server-side redirects, React Router’s Redirect component will replace the current
location in the history stack with a new location. The new location is specified by the to prop.
Here’s how we’ll be using <Redirect> :
So, if someone tries to access the /admin route while logged out, they’ll be redirected to the
/login route. The information about the current location is passed via the state prop, so that if
the authentication is successful, the user can be redirected back to the page they were originally
trying to access.
Custom Routes
A custom route is a fancy way of describing a route nested inside a component. If we need to
make a decision whether a route should be rendered or not, writing a custom route is the way to
go.
Create a new file PrivateRoute.js in the src directory and add the following content:
return (
<Route {...rest}>
{fakeAuth.isAuthenticated === true ?
<Component />
:
<Redirect to={{ pathname: "/login", state: { from: location } }} />
}
</Route>
);
};
As you can see, in the function definition we’re destructuring the props we receive into a
Component prop and a rest prop. The Component prop will contain whichever component our
<PrivateRoute> is protecting (in our case, Admin ). The rest prop will contain any other props
we’ve been passed.
We then return a <Route> component, which renders either the protected component or
redirects us to our /login route, depending on whether or not the user is logged in. This is
determined here by a fakeAuth.isAuthenticated property, which is imported from the <Login>
component.
The good thing about this approach is that it’s evidently more declarative and <PrivateRoute> is
reusable.
In a real-world app, you need to validate any request for a protected resource on your server. This
is because anything that runs in the client can potentially be reverse engineered and tampered
with. For example, in the above code one can just open React’s dev tools and change the value of
isAuthenticated , thus gaining access to the protected area.
Authentication in a React app is worthy of a tutorial of its own, but one way to implement it would
be using JSON Web Tokens. For example, you could have an endpoint on your server which
accepts a username and password combination. When it receives these (via Ajax), it checks to
see if the credentials are valid. If so, it responds with a JWT, which the React app saves (for
example in sessionStorage ), and if not, it sends a 401 Unauthorized response back to the client.
Assuming a successful login, the client would then send the JWT as a header along with any
request for a protected resource. This would then be validated by the server before it sent a
response.
When storing passwords, the server would not store them in plaintext. Rather, it would encrypt
them—for example, using bcryptjs.
Now let’s implement our protected route. Alter src/App.js like so:
<Switch>
<Route exact path="/"><Home /></Route>
<Route path="/category"><Category /></Route>
<Route path="/products"><Products /></Route>
<Route path="/login"><Login /></Route>
<PrivateRoute path="/admin" component={Admin} />
</Switch>
</div>
);
}
As you can see, we’ve added an <Admin> component to the top of the file and are including our
<PrivateRoute> within the <Switch> component. As mentioned previously, this custom route
renders the <Admin> component if the user is logged in. Otherwise, the user is redirected to
/login .
if (redirectToReferrer) {
return <Redirect to={from} />;
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
}
By now, there’s hopefully nothing too tricky going on here. We use the useLocation hook to
access the router’s location prop, from which we grab the state property. We then use object
destructuring to get a value for the URL the user was trying to access before being asked to log
in. If this isn’t present, we set it to { pathname: "/" } .
Once the button is clicked, the fakeAuth.authenticate method is executed, which sets
fakeAuth.isAuthenticated to true and (in a callback function) updates the value of
redirectToReferrer to true . This causes the component to re-render and the user to be
redirected.
Working Demo
Let’s fit the puzzle pieces together, shall we? Here’s the final demo of the application we built
using React router.
Summary
As you’ve seen in this guide, React Router is a powerful library that complements React for
building better, declarative routes. Unlike the prior versions of React Router, in v5, everything is
“just components”. Moreover, the new design pattern perfectly fits into the React way of doing
things.
In this tutorial, we learned:
Finally, we learned some advanced routing techniques for creating the final demo for protected
routes.
Chapter
2
20 Essential
React Tools
Camilo Reyes
The React ecosystem has evolved into a growing list of dev tools and libraries. The plethora of
tools is a true testament to React’s popularity. For devs, it can be a dizzying exercise to navigate
this maze that changes at neck-breaking speed. To help navigate your course, below is a list of
essential React tools, techniques and skills for 2020 and beyond.
Hooks
Website: reactjs.org/docs/hooks-intro.html
Repository: github.com/facebook/react
GitHub stars: 157,000+
Developer: Facebook
Current version: 16.14.0
Contributors: 1,500+
While not strictly a tool, any developer working with React in the 2020s needs to be familiar with
hooks. These are a new addition to React as of version 16.8 which unlock useful features in
function components. For example, the useState hook allows a function component to have its
own state, whereas useEffect allows you to perform side effects after the initial render—for
example, manipulating the DOM or data fetching. Hooks can be used to replicate lifecycle
methods in functional components and allow you to share code between components.
Pros:
Cons:
If you’d like to find out more about hooks, then check out our tutorial, “React Hooks: How to Get
Started & Build Your Own”.
Function Components
Website: reactjs.org/docs/components-and-props.html
Repository: github.com/facebook/react
GitHub stars: 157,000+
Developer: Facebook
Current version: 16.14.0
Contributors: 1,500+
With the advent of hooks, function components—a declarative way to create JSX markup
without using a class—are becoming more popular than ever. They embrace the functional
paradigm because they don’t manage state in lifecycle methods. This emphasizes focus on the
UI markup without much logic. Because the component relies on props, it becomes easier to test.
Props have a one-to-one relationship with the rendered output.
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Pros:
focuses on the UI
testable component
less cognitive load when thinking about the component
Cons:
no lifecycle methods
Create React App is the quintessential tool for firing up a new React project. It manages all React
dependencies via a single npm package. No more dealing with Babel, webpack, and the rest. All it
takes is one command to set up a local development environment, with React, JSX, and ES6
support. But that’s not all. Create React App also offers hot module reloading (your changes are
immediately reflected in the browser when developing), automatic code linting, a test runner and
a build script to bundle JS, CSS, and images for production.
And it’s even easier to upgrade later. The entire dependency tool chain gets upgraded with
react-scripts in package.json :
npm i react-scripts@latest
Pros:
Cons:
If you’d like to find out more about using Create React App, please consult our tutorial, “Create
React App: Get React Projects Ready Fast”.
Proxy Server
Website: create-react-app.dev/docs/proxying-api-requests-in-development
Repository: github.com/facebook/create-react-app
GitHub stars: 82,000+
Developer: Facebook
Current version: 3.4.1
Contributors: 800+
Starting from version react-scripts@0.2.3 or higher, it’s possible to proxy API requests. This
allows the back-end API and local Create React App project to co-exist. From the client side,
making a request to /my-killer-api/get-data routes the request through the proxy server. This
seamless integration works both in local dev and post-build. If local dev runs on port
localhost:3000 , then API requests go through the proxy server. Once you deploy static assets, it
goes through whatever back end hosts these assets.
"proxy": "http://localhost/my-killer-api-base-url"
If the back-end API is hosted with a relative path, set the home page:
"homepage": "/relative-path"
Pros:
Con
PropTypes
Website: npmjs.com/package/prop-types
Repository: github.com/facebook/prop-types
GitHub stars: 3,600+
Developer: Facebook
Current version: 15.7.2
Contributors: 45+
PropTypes declares the type intended for the React component and documents its intent. This
shows a warning in local dev if the types don’t match. It supports all JavaScript primitives such as
Boolean , Number , and String . It can document which props are required via isRequired .
For example:
import PropTypes;
MyComponent.propTypes = {
boolProperty: PropTypes.bool,
numberProperty: PropTypes.number,
requiredProperty: PropTypes.string.isRequired
};
Pros:
Cons:
TypeScript
Website: typescriptlang.org
Repository: github.com/Microsoft/TypeScript
GitHub stars: 65,000+
Developer: Microsoft
Current version: 4.0.3
Contributors: 530+
JavaScript that scales for React projects with compile type checking. This supports all React
libraries and tools with type declarations. It’s a superset of JavaScript, so it’s possible to opt out
of the type checker. This both documents intent and fails the build when it doesn’t match. In
Create React App projects, turn it on by passing in --template typescript when creating your
app. TypeScript support is available starting from version react-script@2.1.0 .
interface MyComponentProps {
boolProp?: boolean; // optional
numberProp?: number; // optional
requiredProp: string;
}
Pros:
Cons:
If you’d like to find out more about using TypeScript with React, check out “React with
TypeScript: Best Practices”.
Redux
Website: redux.js.org/
Repository: github.com/reduxjs/redux
GitHub stars: 54,000+
Developers: Dan Abramov and Andrew Clark
Current version: 4.0.5
Contributors: 800+
Predictable state management container for JavaScript apps. This tool comes with a store that
manages state data. State mutation is only possible via a dispatch message. The message object
contains a type that signals to the reducer which mutation to fire. The recommendation is to
keep everything in the app in a single store. Redux supports multiple reducers in a single store.
Reducers have a one-to-one relationship between input parameters and output state. This
makes reducers pure functions.
default:
return state;
}
};
Pros:
React-Redux
Website: react-redux.js.org
Repository: github.com/reduxjs/redux
GitHub stars: 18,500+
Developer: Redux team
Current version: 7.2.1
Contributors: 220+
If you want to use Redux in your React apps, you’ll soon discover the official React bindings for
Redux. This comes in two main modules: Provider and connect . The Provider is a React
component with a store prop. This prop is how a single store hooks up to the JSX markup. The
connect function takes in two parameters: mapStateToProps , and mapDispatchToProps . This is
where state management from Redux ties into component props. As state mutates, or
dispatches fire, bindings take care of setting state in React.
connect(mapStateToProps, mapDispatchToProps)(SimpleComponent);
Pros:
Cons:
It should also be noted that, with the introduction of hooks and React’s Context API, it’s possible
to replace Redux in some React applications. You can read more about that in “How to Replace
Redux with React Hooks and the Context API”.
React Router
Website: reactrouter.com
Repository: github.com/ReactTraining/react-router
GitHub stars: 42,000+
Developer: React Training
Current version: 5.2.0
Contributors: 640+
React Router is the de facto standard routing library for React. When you need to navigate
through a React application with multiple views, you’ll need a router to manage the URLs. React
Router takes care of that, keeping your application UI and the URL in sync.
Recent versions of React Router have introduced hooks, which let you access the state of the
router and perform navigation from inside your components, as well as a newer route rendering
pattern:
<Route path="/">
<Home />
</Route>
If you’d like to find out more about what React Router can do, please see “React Router v5: The
Complete Guide”.
Pros:
Cons:
without additional configuration, data is downloaded for views a user might not visit
client-side routing (whereby JavaScript is converted to HTML) has SEO implications
ESLint
Website: eslint.org
Repository: github.com/eslint/eslint
GitHub stars: 17,000+
Developer: Nicholas C. Zakas and the ESLint team
Current version: 7.11.0
Contributors: 820+
ESLint is a linting tool that can be used to keep your code style consistent, enforce code quality
and spot potential errors and bad patterns ahead of time. It offers a plugin with React-specific
linting rules and is often used in conjunction with Airbnb’s React style guide.
Although ESLint can be run via the command line, it pays dividends to spend some time
integrating it into your editor of choice. Many of the problems it finds can be automatically fixed
and, coupled with a tool like Prettier, ESLint can seriously help improve the quality of your code,
as well as your overall developer experience.
Anyone using Create React App will notice that it ships with ESLint already enabled and provides
a minimal set of rules intended to find common mistakes.
Pros:
flexible: any rule can be toggled, and many rules have extra settings that can be tweaked
extensible: many plugins available
support for JSX and TypeScript
Cons:
If you’d like to learn more about ESLint, please consult our tutorial, “Up and Running with ESLint
— the Pluggable JavaScript Linter”.
Lodash
Website: lodash.com
Repository: github.com/lodash/lodash
GitHub stars: 46,500+
Developer: John-David Dalton and Lodash team
Current version: 4.17.20
Contributors: 300+
Lodash is a modern JavaScript utility library useful for React components. For example, React
form input events like onChange fire once per keystroke. If the component gets data from a
back-end API, it fires requests once per keystroke. This spams the back-end API and causes
issues when many people use the UI. Lodash comes with debounced events, which fires one API
request with many keystrokes.
Pros:
modular dependency
plays well with code-splitting
easy to use
Cons:
Axios
Website: npmjs.com/package/axios
Repository: github.com/axios/axios
GitHub stars: 77,500+
Developer: axios team
Current version: 0.20.0
Contributors: 250+
Making HTTP requests to fetch or save data is one of the most common tasks a client-side
JavaScript application will need to do. And there is arguably no library better suited to the task
than axios, a Promise-based HTTP client with an easy-to-use API. The tool supports
async ... await syntax to make Ajax requests from the browser. It supports error handling in case
there are errors via catch . The tool’s API supports HTTP requests such as GET, DELETE, POST,
PUT, and PATCH. This also plays well with Promise API calls like Promise.all() to send HTTP
requests in parallel.
Similar to jQuery’s $.ajax function, you can make any kind of HTTP request by passing an
options object to axios:
axios({
method: 'post',
url: '/login',
data: {
user: 'camilo',
lastName: 'reyes'
}
});
Pros:
promise based
supports async/await
supports error handling
Cons:
If you’d like to learn more about using axios in your projects, see “Introducing Axios, a Popular,
Promise-based HTTP Client”.
Jest
Website: jestjs.io
Repository: github.com/facebook/jest
GitHub stars: 32,500+
Developer: Facebook
Current version: 26.5.3
Contributors: 1,000+
Jest is a testing framework with a focus on simplicity for JavaScript projects. The good news is it
comes built-in with Create React App. It works with projects that use Babel, TypeScript, and
Node. There’s no configuration on most React projects. Tests can run in watch mode, which
keeps track of code changes and reruns tests. The API contains it , and expect to quickly get
started.
A sanity check to make sure tests execute is:
Pros:
Cons:
If you’d like to find out how you can use Jest in your React projects, please see “How to Test
React Components Using Jest”.
Enzyme
Website: enzymejs.github.io/enzyme/
Repository: github.com/enzymejs/enzyme
GitHub stars: 19,000+
Developer: Airbnb
Current version: 3.11.0
Contributors: 350+
Enzyme is a JavaScript testing utility for React that makes it easier to test components. The API
is meant to be as intuitive as jQuery for component traversal. To get Enzyme, it needs two
packages: enzyme , and a separate adapter. The adapter must be compatible with the version of
React. For example, enzyme-adapter-react-16 for React ^16.4.0 , enzyme-adapter-react-16.3
for ~16.3.0 , so on and so forth. The adapter needs a configuration file setupTest.js to
integrate with Jest.
Pros:
supports React components
supports Jest test framework
intuitive API
Cons:
Shallow Renderer
Website: enzymejs.github.io/enzyme/docs/api/shallow.html
Repository: github.com/airbnb/enzyme
GitHub stars: 19,000+
Developer: Airbnb
Current version: 3.11.0
Contributors: 350+
This is shallow rendering useful for limiting tests to one level deep. It renders the parent
component without affecting its children in a tree hierarchy. This isolates the test and makes
assertions more robust. Shallow rendering supports a good chunk of the Enzyme API for
traversing components. The shallow API does call lifecycle methods like componentDidMount
and componentDidUpdate during render. With hooks, the shallow renderer does not call
useEffect . One tip is do console.log(component.debug()) to inspect what the shallow renderer
sees.
Pros:
isolates test
full featured API
allows quick debugging
Cons:
must navigate the sea of options in Enzyme’s API to find this diamond in the rough
Storybook
Website: storybook.js.org
Repository: github.com/storybookjs/storybook
GitHub stars: 54,000+
Developer: Storybook
Current version: 6.0.26
Contributors: 1100+
This is an open-source tool for manual testing of React components in isolation. Storybook
provides a sandbox to build components to get into hard to reach edge cases. It allows mocking
so it can render components in key states that are hard to reproduce. Setup is automatic with
Create React App when using react-scripts . Each story in Storybook can target a single
component with many states. The story files have a convention like component.stories.js so
one can quickly find them.
Pros:
Cons:
You can find out more about Storybook in our guide, “React Storybook: Develop Beautiful User
Interfaces with Ease”.
React Bootstrap
Website: react-bootstrap.github.io
Repository: github.com/react-bootstrap/react-bootstrap
GitHub stars: 18,400+
Developer: react-bootstrap
Current version: 1.3.0
Contributors: 300+
This is the most popular front-end framework rebuilt for React. Every Bootstrap component is
built from scratch as a React component. This replaces Bootstrap JavaScript and nukes
dependencies like jQuery. The latest version supports Bootstrap 4.5. React Bootstrap works with
the thousands of Bootstrap themes already found in version 4. Each component has accessibility
in mind and is accessible by default. It supports Create React App out of the box, and custom
themes are also supported.
Pros:
Cons:
Material-UI offers popular React components for faster and easier web development. It allows
building your own design system or starting with Material Design. There are templates and
themes available, both premium and free. Premium themes have a price tag depending on
functionality. Material-UI comes via an npm package for quick installation.
Image source
Pros:
build a powerful UI with little effort
offers many components
offers many templates
Cons:
React DevTools
Website: reactjs.org/blog/2019/08/15/new-react-devtools.html
Repository: github.com/facebook/react
GitHub stars: 157,000+
Developer: Facebook
Current version: 16.14.0
Contributors: 1,500+
One of the most important tools in any React developer’s toolbelt should be the React Developer
Tools—a browser extension for both Chrome and Firefox. This allows you to easily inspect a
React tree, including the component hierarchy, props, state, and more.
Once installed, the dev tools will give you two new tabs in your browser console—Components
and Profiler. Clicking the former will show you all of the components in the current tree and allow
you to filter them by name, whereas the latter allows you to record performance information
about your React app.
This is a must-have tool when it comes to debugging a React app that consists of more than a
handful of components.
Pros
Cons
Let’s round this list off with … another list! This time awesome-react—a GitHub repo containing a
collection of awesome things relating to the React ecosystem.
The repo has a Tools section that contains many of the tools listed in this guide (and a whole lot
more besides), as well as sections on Tutorials, Demos, Videos, Conference Talks, ReactNative,
GraphQL and more. Whatever you’re looking for in the world of React, this is a great place to
start.
Pros
Cons
Conclusion
As shown, React’s ecosystem has exploded within the last few years. It’s the tool of choice for
enterprise wanting to reuse React components in a consistent suite. Each tool is standalone with
few interdependencies. My recommendation is to give these tools at least a try.
Chapter
3
React with
TypeScript: Best
Practices
JavaScript Joe
React and TypeScript are two awesome technologies used by a lot of developers these days.
Knowing how to do things can get tricky, and sometimes it’s hard to find the right answer. Not to
worry. We’ve put together the best practices along with examples to clarify any doubts you may
have.
The reason you might use them together would be to get the benefits of a statically typed
language (TypeScript) for your UI. This means more safety and fewer bugs shipping to the front
end.
A common question that’s always good to review is whether TypeScript compiles your React
code. The way TypeScript works is similar to this interaction:
So the answer is yes, it does! But later, when we cover the tsconfig.json settings, most of the
time you’ll want to use "noEmit": true . What this means is TypeScript will not emit JavaScript
out after compilation. This is because typically, we’re just utilizing TS to do our TypeScript.
The output is handled, in a CRA setting, by react-scripts . We run yarn build and react-
scripts bundles the output for production.
To recap, TypeScript compiles your React code to type-check your code. It doesn’t emit any
JavaScript output (in most scenarios). The output is still similar to a non-TypeScript React
project.
Can TypeScript Work with React and webpack?
Yes, TypeScript can work with React and webpack. Lucky for you, the webpack documentation
has a guide on that.
Hopefully, that gives you a gentle refresher on how the two work together. Now, on to best
practices!
Best Practices
We’ve researched the most common questions and put together this handy list of the most
common use cases for React with TypeScript. This way, you can use this guide as a reference in
your own projects.
Configuration
One of the least fun, yet most important parts of development is configuration. How can we set
things up in the shortest amount of time that will provide maximum efficiency and productivity?
We’ll discuss project setup including:
tsconfig.json
ESLint
Prettier
VS Code extensions and settings.
Project Setup
The quickest way to start a React/TypeScript app is by using create-react-app with the
TypeScript template. You can do this by running:
This will get you the bare minimum to start writing React with TypeScript. A few noticeable
differences are:
The tsx is for “TypeScript JSX”. The tsconfig.json is the TypeScript configuration file, which
has some defaults set. The react-app-env.d.ts references the types of react-scripts , and
helps with things like allowing for SVG imports.
tsconfig.json
Lucky for us, the latest React/TypeScript template generates tsconfig.json for us. However,
they add the bare minimum to get started. We suggest you modify yours to match the one below.
We’ve added comments to explain the purpose of each option as well:
{
"compilerOptions": {
"target": "es5", // Specify ECMAScript target version
"lib": [
"dom",
"dom.iterable",
"esnext"
], // List of library files to be included in the compilation
"allowJs": true, // Allow JavaScript files to be compiled
"skipLibCheck": true, // Skip type checking of all declaration files
"esModuleInterop": true, // Disables namespace imports and enables CJS/AMD/UMD style imports
"allowSyntheticDefaultImports": true, // Allow default imports from modules with no default export
"strict": true, // Enable all strict type checking options
"forceConsistentCasingInFileNames": true, // Disallow inconsistently-cased file references
"module": "esnext", // Specify module code generation
"moduleResolution": "node", // Resolve modules using Node.js style
"isolatedModules": true, // Unconditionally emit imports for unresolved files
"resolveJsonModule": true, // Include modules imported with .json extension
"isolatedModules": true, // Transpile each file as a separate module
"noEmit": true, // Do not emit output (meaning do not compile code, only perform type checking)
"jsx": "react" // Support JSX in .tsx files
"sourceMap": true, // Generate corresponding .map file
"declaration": true, // Generate corresponding .d.ts file
"noUnusedLocals": true, // Report errors on unused locals
"noUnusedParameters": true, // Report errors on unused parameters
"incremental": true // Enable incremental compilation
"noFallthroughCasesInSwitch": true // Report errors for fallthrough cases in switch statement
},
"include": [
"src/**/*" // The files TypeScript should type check
],
"exclude": ["node_modules", "build"] // The files to not type check
}
In order to ensure that your code follows the rules of the project or your team, and the style is
consistent, it’s recommended you set up ESLint and Prettier. To get them to play nicely, follow
these steps to set it up.
module.exports = {
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
extends: [
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
ecmaFeatures: {
jsx: true, // Allows for the parsing of JSX
},
},
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the
// extended configs
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
},
settings: {
react: {
version: 'detect', // Tells eslint to automatically detect the version of React
},
},
};
module.exports = {
semi: true,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 4,
};
module.exports = {
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
extends: [
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
+ 'prettier/@typescript-eslint',
+ 'plugin:prettier/recommended',
...
These recommendations come from a community resource written called “Using ESLint and
Prettier in a TypeScript Project”, by Robert Cooper. If you visit this resource, you can read more
about the “why” behind these rules and configurations.
We’ve added ESLint and Prettier and the next step to improve our DX is to automatically fix/
prettify our code on save.
First, install the ESLint extension for VS Code. This will allow ESLint to integrate with your editor
seamlessly.
Next, update your Workspace settings by adding the following to your .vscode/settings.json :
{
"eslint.autoFixOnSave": true,
"eslint.validate": [
"javascript",
"javascriptreact",
{ "language": "typescript", "autoFix": true },
{ "language": "typescriptreact", "autoFix": true }
],
"editor.formatOnSave": true,
"[javascript]": {
"editor.formatOnSave": false
},
"[javascriptreact]": {
"editor.formatOnSave": false
},
"[typescript]": {
"editor.formatOnSave": false
},
"[typescriptreact]": {
"editor.formatOnSave": false
}
}
This will allow VS Code to work its magic and fix your code when you save. It’s beautiful!
These suggestions also come from the previously linked article “Using ESLint and Prettier in a
TypeScript Project”, by Robert Cooper.
Components
One of the core concepts of React is components. Here, we’ll be referring to standard
components as of React v16.8, meaning ones that use hooks as opposed to classes.
In general, there’s much to be concerned with for basic components. Let’s look at an example:
Notice the key difference here. In the first example, we’re writing our function as a function
declaration. We annotate the return type with React.Node because that’s what it returns. In
contrast, the second example uses a function expression. Because the second instance returns a
function, instead of a value or expression, we annotate the function type with React.FC for
React “Function Component”.
It can be confusing to remember the two. It’s mostly a matter of design choice. Whichever you
choose to use in your project, use it consistently.
To read more about React.FC , look here, and read here for more on React.ReactNode .
Props
The next core concept we’ll cover is props. You can define your props using either an interface or
a type. Let’s look at another example:
interface Props {
name: string;
color: string;
}
type OtherProps = {
name: string;
color: string;
}
// Notice here we're using the function declaration with the interface Props
function Heading({ name, color }: Props): React.ReactNode {
return <h1>My Website Heading</h1>
}
// Notice here we're using the function expression with the type OtherProps
const OtherHeading: React.FC<OtherProps> = ({ name, color }) =>
<h1>My Website Heading</h1>
When it comes to types or interfaces, we suggest following the guidelines presented by the
react-typescript-cheatsheet community:
“Always use interface for public API’s definition when authoring a library or 3rd-party ambient
type definitions.”
“Consider using type for your React Component Props and State, because it is more
constrained.”
You can read more about the discussion and see a handy table comparing types vs interfaces
here.
Let’s look at one more example so we can see something a little bit more practical:
type Props = {
/** color to use for the background */
color?: string;
/** standard children prop: accepts any valid React Node */
children: React.ReactNode;
/** callback function passed to the onClick handler*/
onClick: () => void;
}
In this <Button /> component, we use a type for our props. Each prop has a short description
listed above it to provide more context to other developers. The ? after the prop named color
indicates that it’s optional. The children prop takes a React.ReactNode because it accepts
everything that’s a valid return value of a component (read more here). To account for our
optional color prop, we use a default value when destructuring it. This example should cover
the basics and show you have to write types for your props and use both optional and default
values.
In general, keep these things in mind when writing your props in a React and TypeScript project:
Always add descriptive comments to your props using the TSDoc notation /** comment */ .
Whether you use types or interfaces for your component props, use them consistently.
When props are optional, handle appropriately or use default values.
Hooks
Luckily, the TypeScript type inference works well when using hooks. This means you don’t have
much to worry about. For instance, take this example:
This is one area in React and TypeScript that shines. It means you don’t have to do much. Things
just work and it’s beautiful.
On the rare occasions where you need to initialize a hook with a null-ish value, you can make use
of a generic and pass a union to correctly type your hook. See this instance:
type User = {
email: string;
id: string;
}
The other place where TypeScript shines with Hooks is with userReducer , where you can take
advantage of discriminated unions. Here’s a useful example:
The beauty here lies in the usefulness of discriminated unions. Notice how Action has a union of
two similar-looking objects. The property type is a string literal. The difference between this
and a type string is that the value must match the literal string defined in the type. This means
your program is extra safe because a developer can only call an action that has a type key set to
"SET_ONE" or "SET_TWO" .
As you can see, Hooks don’t add much complexity to the nature of a React and TypeScript
project. If anything, they lend themselves well to the duo.
This section is to cover the most common use cases where people stumble when using
TypeScript with React. We hope by sharing this, you’ll avoid the pitfalls and even share this
knowledge with others.
One of the most common cases is correctly typing the onChange used on an input field in a form.
Here’s an example:
Sometimes you want to take component props declared for one component and extend them to
use them on another component. But you might want to modify one or two. Well, remember how
we looked at the two ways to type component props, types or interfaces? Depending on which
you used determines how you extend the component props. Let’s first look at the way using
type :
type ButtonProps = {
/** the background color of the button */
color: string;
/** the text to show inside the button */
text: string;
}
If you declared your props using an interface , then we can use the keyword extends to
essentially “extend” that interface but make a modification or two:
interface ButtonProps {
/** the background color of the button */
color: string;
/** the text to show inside the button */
text: string;
}
Both methods solve the problem. It’s up to you to decide which to use. Personally, extending an
interface feels more readable, but ultimately, it’s up to you and your team.
You can read more about both concepts in the TypeScript Handbook:
Intersection Types
Extending Interfaces
Third-party Libraries
Whether it’s for a GraphQL client like Apollo or for testing with something like React Testing
Library, we often find ourselves using third-party libraries in React and TypeScript projects.
When this happens, the first thing you want to do is see if there’s a @types package with the
TypeScript type definitions. You can do so by running:
#yarn
yarn add @types/<package-name>
#npm
npm install @types/<package-name>
#yarn
yarn add @types/jest
#npm
npm install @types/jest
This would then give you added type-safety whenever you’re using Jest in your project.
The @types namespace is reserved for package type definitions. They live in a repository called
DefinitelyTyped, which is partially maintained by the TypeScript team and partially the
community.
The short answer is “it depends”. Most of the time, they can go under devDependencies if you’re
building a web application. However, if you’re writing a React library in TypeScript, you may want
to include them as dependencies .
There are a few answers to this on Stack Overflow, which you may check out for further
information.
If you don’t find a @types package on npm, then you essentially have two options:
The first option means you create a file based on the package name and put it at the root. If, for
instance, we needed types for our package banana-js , then we could create a basic declaration
file called banana-js.d.ts at the root:
declare module 'banana-js';
This won’t provide you type safety but it will unblock you.
A more thorough declaration file would be where you add types for the library/package:
If you’ve never written a declaration file, then we suggest you take a look at the guide in the
official TypeScript Handbook.
Summary
Using React and TypeScript together in the best way takes a bit of learning due to the amount of
information, but the benefits pay off immensely in the long run. In this guide, we covered
configuration, components, props, hooks, common use cases, and third-party libraries. Although
we could dive deeper into a lot of individual areas, this should cover the 80% needed to help you
follow best practices.
If you’d like to get in touch, share feedback on this guide or chat about using the two
technologies together, you can reach me on Twitter @jsjoeio.
Further Reading
If you’d like to dive deeper, here are some resources we suggest:
react-typescript-cheatsheet
Another fantastic resource is the TypeScript Handbook. This is kept up to date by the TypeScript
team and provides examples and an in-depth explanation behind the inner workings of the
language.
TypeScript Playground
Did you know you can test out React with TypeScript code right in the browser? All you have to
do is import React. Here’s a link to get you started.
Chapter
4
React vs
Angular: An In-
depth
Comparison
Pavels Jelisejevs
Should I choose Angular or React? Each framework has a lot to offer and it’s not easy to choose
between them. Whether you’re a newcomer trying to figure out where to start, a freelancer
picking a framework for your next project, or an enterprise-grade architect planning a strategic
vision for your company, you’re likely to benefit from having an educated view on this topic.
To save you some time, let me tell you something up front: this guide won’t give a clear answer on
which framework is better. But neither will hundreds of other guides with similar titles. I can’t tell
you that, because the answer depends on a wide range of factors which make a particular
technology more or less suitable for your environment and use case.
Since we can’t answer the question directly, we’ll attempt something else. We’ll compare Angular
and React, to demonstrate how you can approach the problem of comparing any two
frameworks in a structured manner on your own and tailor it to your environment. You know, the
old “teach a man to fish” approach. That way, when both are replaced by a BetterFramework.js in
a year’s time, you’ll be able to re-create the same train of thought once more.
Where to Start?
Before you pick any tool, you need to answer two simple questions: “Is this a good tool per se?”
and “Will it work well for my use case?” Neither of them mean anything on their own, so you
always need to keep both of them in mind. All right, the questions might not be that simple, so
we’ll try to break them down into smaller ones.
Questions on the tool itself:
Using this set of questions, you can start your assessment of any tool, and we’ll base our
comparison of React and Angular on them as well.
There’s another thing we need to take into account. Strictly speaking, it’s not exactly fair to
compare Angular to React, since Angular is a full-blown, feature-rich framework, while React just
a UI component library. To even the odds, we’ll talk about React in conjunction with some of the
libraries often used with it.
Maturity
An important part of being a skilled developer is being able to keep the balance between
established, time-proven approaches and evaluating new bleeding-edge tech. As a general rule,
you should be careful when adopting tools that haven’t yet matured due to certain risks:
React
React is developed and maintained by Facebook and used in their products, including Instagram
and WhatsApp. It has been around for around since 2013, so it’s not exactly new. It’s also one of
the most popular projects on GitHub, with more than 150,000 stars at the time of writing. Some
of the other notable companies using React are Airbnb, Uber, Netflix, Dropbox, and Atlassian.
Sounds good to me.
Angular
Angular has been around since 2016, making it slightly younger than React, but it’s also not a
new kid on the block. It’s maintained by Google and, as mentioned by Igor Minar, even in 2018
was used in more than 600 hundred applications in Google such as Firebase Console, Google
Analytics, Google Express, Google Cloud Platform and more. Outside of Google, Angular is used
by Forbes, Upwork, VMWare, and others.
Features
Like I mentioned earlier, Angular has more features out of the box than React. This can be both a
good and a bad thing, depending on how you look at it.
Both frameworks share some key features in common: components, data binding, and platform-
agnostic rendering.
Angular
Angular provides a lot of the features required for a modern web application out of the box. Some
of the standard features are:
dependency injection
templates, based on an extended version of HTML
class-based components with lifecycle hooks
routing, provided by @angular/router
Ajax requests using @angular/common/http
@angular/forms for building forms
component CSS encapsulation
XSS protection
code splitting and lazy loading
test runner, framework and utilities for unit-testing.
Some of these features are built into the core of the framework and you don’t have an option not
to use them. This requires developers to be familiar with features such as dependency injection
to build even a small Angular application. Other features such as the HTTP client or forms are
completely optional and can be added on an as-needed basis.
React
With React, you’re starting with a more minimalistic approach. If we’re looking at just React,
here’s what we have:
instead of classic templates, it has JSX, an XML-like language built on top of JavaScript
class-based components with lifecycle hooks or simpler functional components
state management using setState and hooks.
XSS protection
code splitting and lazy loading
error handling boundaries
utilities for unit-testing components
Out of the box, React does not provide anything for dependency injection, routing, HTTP calls, or
advanced form handling. You are expected to choose whatever additional libraries to add based
on your needs which can be both a good and a bad thing depending on how experienced you are
with these technologies. Some of the popular libraries that are often used together with React
are:
The teams I’ve worked with have found the freedom of choosing your libraries liberating. This
gives us the ability to tailor our stack to particular requirements of each project, and we haven’t
found the cost of learning new libraries that high.
React
Several important things come to mind when thinking about React: JSX, components, and hooks.
JSX
In contrast to most frameworks, React doesn’t have a separate templating language. Instead of
following a classical approach of separating markup and logic, React decided to combine them
within components using JSX, an XML-like language that allows you to write markup directly in
your JavaScript code.
While the merits of mixing markup with JavaScript might be debatable, it has an indisputable
benefit: static analysis. If you make an error in your JSX markup, the compiler will emit an error
instead of continuing in silence. This helps by instantly catching typos and other silly errors.
Using JSX caught on in different projects—such as MDX, which allows using JSX in markdown
files.
Components
Class components allow you to write your code using ES classes and structure the component
logic into methods. They also allow you to use React’s traditional lifecycle methods to run
custom logic when a component is mounted, updated, unmounted, and so on. Even though this
notation is easier to understand for people familiar with OOP programming, you need to be
aware of all the subtle nuances that JS has—for example, how this works, and not forgetting to
bind event handlers.
Functional components are defined as simple functions. They are often pure and provide a clear
mapping between the input props and the rendered output. Functional code is usually less
coupled and easier to reuse and test. Before the introduction of hooks, functional components
could not be stateful and did not have an alternative to the lifecycle methods.
There’s a trend among React developers to ditch class components in favor of simpler functional
components, but with hooks being a newer feature, you’ll usually see a mix of both approaches in
larger React projects.
Hooks
Hooks are a new feature of React introduced in version 16.8. They are functions that allow you to
class component state and lifecycle method features in functional components. There are two
hooks provided by React: useState for managing the state, and useEffect for creating side
effects—such as loading data or manually editing the DOM.
Hooks have been introduced to make functional components simpler and more composable. You
can now split large functions into smaller atomic parts, allowing you to divide up related pieces of
functionality—separating them from the rendering logic and reusing it in different components.
Hooks are a cleaner alternative to using class components and other patterns, such as render
functions and higher-order components—which can quickly get overly complicated.
React provides ways of structuring your application without involving a lot of complicated
abstraction layers. Utilizing functional components together with hooks allows you to write code
that is simpler, more atomic, and reusable. Even though the notion of combining the code and
templates might seem controversial, separating the presentation and application logic into
different functions allows you to achieve similar results.
Angular
Angular has a few interesting things up its sleeve as well, starting from the basic abstractions
such as components, services, and modules, to TypeScript, RxJS, and Angular Elements, as well
as its approach to state management.
Main Concepts
Angular has a higher abstraction level than React, thus introducing more fundamental concepts
to get familiar with. The main ones are:
components: defined as specially decorated ES classes that are responsible for executing the
application logic and rendering the template
services: classes responsible for the implementation of business and application logic, used
by components
modules: essentially DI containers for wiring related components, services, pipes, and other
entities together.
Angular makes heavy use of classes as well as concepts such as DI, which are less popular in the
world of front-end development, but should be familiar to anyone with back-end development
experience.
TypeScript
TypeScript is a new language built on top of JavaScript and developed by Microsoft. It’s a
superset of JavaScript ES2015 and includes features from newer versions of the language. You
can use it instead of Babel to write state-of-the-art JavaScript. It also features an extremely
powerful typing system that can statically analyze your code by using a combination of
annotations and type inference.
There’s also a more subtle benefit. TypeScript has been heavily influenced by Java and .NET, so if
your developers have a background in one of these languages, they’re likely to find TypeScript
easier to learn than plain JavaScript (notice how we switched from the tool to your personal
environment). Although Angular was the first major framework to actively adopt TypeScript, it’s
now getting traction in a lot of other projects as well, such as Deno (a TypeScript native runtime),
Puppeteer, and TypeORM.
It’s also possible (and wise) to use TypeScript together with React.
RxJS
RxJS is a reactive programming library that allows for more flexible handling of asynchronous
operations and events. It’s a combination of the Observer and Iterator patterns blended with
functional programming. RxJS allows you to treat anything like a continuous stream of values and
perform various operations on it such as mapping, filtering, splitting, or merging.
The library has been adopted by Angular in its HTTP module as well for some internal use. When
you perform an HTTP request, it returns an Observable instead of the usual Promise. This
approach opens the door for interesting possibilities, such as the ability to cancel a request, retry
it multiple times, or work with continuous data streams such as WebSockets. But this is just the
surface. To master RxJS, you’ll need to know your way around different types of Observables,
Subjects, as well as around a hundred methods and operators.
State Management
Similar to React, Angular components have a concept of a component state. Components can
store data in their class properties and bind the values to their templates. If you want to share the
state across the application, you can move it to a stateful service that can later be injected into
the components. Since reactive programming and RxJS is a first-class citizen in Angular, it’s
common to make use of observables to recalculate parts of the state based on some input. This,
however, can get tricky in larger applications since changing some variables can trigger a multi-
directional cascade of updates that’s difficult to follow. There are libraries for Angular that allow
you to simplify state management at scale. We’ll have a closer look at them later on.
Angular Elements
Angular elements provide a way to package Angular components as custom elements. Also
known as web components, custom elements are a framework-agnostic standardized way to
create custom HTML elements that are controlled by your JavaScript code. Once you define
such an element and add it to the browser registry, it will automatically be rendered everywhere
it’s referenced in the HTML. Angular elements provide an API that creates the necessary
wrapper to implement the custom component API and make it work with Angular’s change
detection mechanism. This mechanism can be used to embed other components or whole
Angular applications into your host application, potentially written in a different framework with a
different development cycle.
We’ve found TypeScript to be a great tool for improving the maintainability of our projects,
especially those with a large codebase or complex domain/business logic. Code written in
TypeScript is more descriptive, and easier to follow and refactor. Even if you’re not going with
Angular, we suggest you consider it for your next JavaScript project. RxJS introduces new ways
of managing data flow in your project, but does require you to have a good grasp of the subject.
Otherwise, it can bring unwanted complexity to your project. Angular elements have the
potential for reusing Angular components, and it’s interesting to see how this plays out in the
future.
Ecosystem
The great thing about open source frameworks is the number of tools created around them.
Sometimes, these tools are even more helpful than the framework itself. Let’s have a look at
some of the most popular tools and libraries associated with each framework.
Angular
Angular CLI
A popular trend with modern frameworks is having a CLI tool that helps you bootstrap your
project without having to configure the build yourself. Angular has Angular CLI for that. It allows
you to generate and run a project with just a couple of commands. All of the scripts responsible
for building the application, starting a development server, and running tests are hidden away
from you in node_modules . You can also use it to generate new code during development and
install dependencies.
Angular introduces an interesting new way of managing dependencies to your project. When
using ng add , you can install a dependency and it will automatically be configured for usage. For
example, when you run ng add @angular/material , Angular CLI downloads Angular Material
from the npm registry and runs its install script that automatically configures your application to
use Angular Material. This is done using Angular schematics. Schematics is a workflow tool that
allows the libraries to make changes to your codebase. This means that the library authors can
provide automatic ways of resolving backward-incompatible issues you might face when
installing a new version.
Component Libraries
An important thing in using any JavaScript framework is being able to integrate them with a
component library of your choice, to avoid having to build everything from scratch. Angular
offers integrations with most of the popular component libraries as well as native libraries of its
own. For example:
ng-bootstrap for using Bootstrap widgets
Material UI, for Google’s Material Design components
NG-ZORRO, a library of components implementing the Ant Design specification
Onsen UI for Angular, a library of components for mobile applications
PrimeNG, a collection of rich Angular components
If the native state management capabilities are not enough for you, there are several popular
third-party libraries available in this area.
The most popular one is NgRx. It’s inspired by React’s Redux but also makes use of RxJS to
watch and recalculate data in the state. Using NgRx can help you enforce an understandable
unidirectional data flow, as well as reduce coupling in your code.
NGXS is another state management library inspired by Redux. In contrast to NgRx, NGXS strives
to reduce boilerplate code by using modern TypeScript features and improving the learning
curve and overall development experience.
Akita is a newer kid on the block, which allows us to keep the state in multiple stores, apply
immutable updates, and use RxJS to query and stream the values.
Ionic Framework
Ionic is a popular framework for developing hybrid mobile applications. It provides a Cordova
container that’s nicely integrated with Angular and a pretty material component library. Using it,
you can easily set up and build a mobile application. If you prefer a hybrid app over a native one,
this is a good choice.
Angular universal
Angular universal is a project that bundles different tools to enable server-side rendering for
Angular applications. It’s integrated with Angular CLI and supports several Node.js frameworks,
such as Express and Hapi, as well as with .NET core.
Augury
Augury is a browser extension for Chrome and Firefox that helps to debug Angular applications
running in development mode. You can use it to explore your component tree, monitor change
detection, and optimize performance issues.
Compodoc
Ngx-admin
Ngx-admin is a popular framework for creating custom dashboards with Angular and using either
Nebular or Angular Material as the component libraries.
There are plenty of other libraries and tools available in the Awesome Angular list.
React
Create React App is a CLI utility for React to quickly set up new projects. Similar to Angular CLI, it
allows you to generate a new project, run the app in development mode, or create a production
bundle. It uses Jest for unit testing, supports application profiling using environment variables,
back-end proxies for local development, TypeScript, Sass, PostCSS, and many other features.
Component Libraries
Similar to Angular, React has a wide variety of component libraries to choose from:
ant-design
Material UI
react-bootstrap
Semantic UI
Onsen UI, optimized for mobile applications
Blueprint, for creating desktop applications
The introduction of hooks has certainly shaken up state management in React. There are
ongoing discussions if there even is a need for a third-party state management library. Even
though hooks address the immediate need for working with the state, other libraries can still
push this further by allowing us to use time-tested implementation patterns, lots of additional
libraries, and development tools.
Redux is a state management library inspired by Flux, but with some simplifications. The key idea
of Redux is that the whole state of the application is represented by a single object, which is
mutated by functions called reducers. Reducers themselves are pure functions and are
implemented separately from the components. This enables better separation of concerns and
testability.
MobX is an alternative library for managing the state of an application. Instead of keeping the
state in a single immutable store, as Redux does, it encourages you to store only the minimal
required state and derives the rest from it. It provides a set of decorators to define observables
and observers and introduce reactive logic to your state.
Styling Libraries
Unlike Angular, React does not provide native CSS encapsulation capabilities, so you need to look
for third-party solutions. There are numerous solutions to this problem, with no clear leader
amongst them. Some of the popular ones are:
Styled Components, a library that allows you to create React components with your styling
applied, as well as style your components
CSS Modules, which allows you to import CSS files and generate unique isolated class names
to reference the styles
Emotion, which combines the approaches of Styled Components and CSS Modules into a
single library
PropTypes
PropTypes is an optional feature of React that allows you to introduce component runtime prop
validation. In contrast to using static type checking with TypeScript, PropTypes will perform type
checks when your application is actually running. This comes in especially handy when
developing libraries when you can’t be sure your clients are using TypeScript, even if you are.
Since React 15.5, prop types have been moved to a separate prop-types library and are now
completely optional. Considering its benefits, we advise you to use it to improve the reliability of
your application.
React Native
React Native is a platform developed by Facebook for creating native mobile applications using
React. Unlike Ionic, which produces a hybrid application, React Native produces a truly native UI.
It provides a set of standard React components that are bound to their native counterparts. It
also allows you to create your components and bind them to native code written in Objective-C,
Java, or Swift.
Next.js
Next.js is a framework for the server-side rendering of React applications. It provides a flexible
way to completely or partially render your application on the server, return the result to the client,
and continue in the browser. It tries to make the complex task of creating universal applications
easier, so the setup is designed to be as simple as possible, with a minimal amount of new
primitives and requirements for the structure of your project.
React Admin
React-admin is a framework for building CRUD-style SPA applications on top of existing REST or
GraphQL APIs. It comes with handy features, such as a UI built with Material Design,
internationalization, theming, data validation, and more.
UI Development Environments
A major trend in front-end development for the last couple of years has been the boom of
development tools that allow you to develop, test, and document your component interactively
and separately from the application. Storybook has established itself as one of the leaders in this
area, with support for both React and Angular. However, there are other alternatives for React.
React Styleguidist, similarly to Storybook, allows you to create interactive documentation of your
components. In contrast to Storybook, the generated UI looks more like an interactive readme
than a separate set of stories. While Storybook shines as a development environment,
Styleguidist is more a documentation tool.
We’ve also mentioned MDX in this guide. It allows you to spice up your Markdown files by adding
interactive JSX components.
Testing Helpers
Enzyme is the de-facto standard choice. It allows you to render your components into a full or
shallow DOM as well as interact with the rendered component. It mostly follows a white box
testing approach, where your tests can reference some of the internals of the component like its
children components, props, or state.
Testing Library follows a different approach and pushes you to interact with your components as
a user would, without knowing the technical implementation. Tests created this way are usually
less brittle and easier to maintain. Although it’s most popular with React, the Testing Library is
also available for Angular.
Gatsby
Gatsby is a static website generator that uses React.js. It allows you to use GraphQL to query the
data for your websites defined in Markdown, YAML, JSON, external APIs, and popular content
management systems.
React 360
React 360 is a library for creating virtual reality applications for browsers. It provides a
declarative React API that’s built on top of the WebGL and WebVR browser APIs, thus making it
easier to create 360 VR experiences.
React Dev Tools is a browser extension for Chrome for debugging React applications that allows
you to traverse the React component tree and see their props and state.
There are plenty of other libraries and tools available in the Awesome React list.
React
With React, the first thing you’ll encounter is JSX. It does seem awkward to write for some
developers. However, it doesn’t add that much complexity: just expressions, which are
JavaScript, and special HTML-like syntax. You’ll also need to learn how to write components, use
props for configuration, and manage internal state. You don’t need to learn a new template
syntax, since all of this is plain JavaScript. While React supports class-based components, with
the introduction of hooks, functional development is getting more popular. This will require you
to understand some basic functional development patterns.
The official tutorial is an excellent place to start learning React. Once you’re done with that, get
familiar with the router. The React Router might be slightly complex and unconventional, but
nothing to worry about. Depending on the size, complexity, and requirements of your project,
you’ll need to find and learn some additional libraries, and this might be the tricky part. But after
that, everything should be smooth sailing.
We were genuinely surprised at how easy it was to get started using React. Even people with a
back-end development background and limited experience in front-end development were able
to catch up quickly. The error messages you might encounter along the way are usually clear and
provide explanations on how to resolve the underlying problem.
The downside is that you’ll need to invest time into choosing the libraries to support your
development activities. Given how many of them are there, this can pose a challenge. But this
can be done along with your development activities after you’ve gotten comfortable with the
framework itself.
Although TypeScript is not required for React, we strongly recommend you assess and adopt it in
your projects.
Angular
Learning Angular will introduce you to more new concepts than React. First of all, you’ll need to
get comfortable with TypeScript. For developers with experience in statically typed languages
such as Java or .NET, this might be easier to understand than JavaScript, but for pure JavaScript
developers, this might require some effort. To start your journey, we can recommend the Tour of
Heroes tutorial.
The framework itself is rich in topics to learn, starting from basic ones such as modules,
dependency injection, decorators, components, services, pipes, templates, and directives, to
more advanced topics such as change detection, zones, AoT compilation, and Rx.js. These are all
covered in the documentation. Rx.js is a heavy topic on its own and is described in much detail on
the official website. While relatively easy to use on a basic level, it gets more complicated when
moving on to advanced topics.
All in all, we noticed that the entry barrier for Angular is higher than for React. The sheer number
of new concepts may be overwhelming to newcomers. And even after you’ve started, the
experience might be a bit rough, since you need to keep in mind things like Rx.js subscription
management, change detection performance, and bananas in a box (yes, this is a piece of actual
advice from the documentation). We often encountered error messages that are too cryptic to
understand, so we had to google them and pray for an exact match.
It might seem that we favor React here, and we definitely do. We’ve had experience onboarding
new developers to both Angular and React projects of comparable size and complexity, and
somehow with React it always went smoother. But, as I said earlier, this depends on a broad
range of factors and might work differently for you.
The npm download statistics shows almost five times more downloads for React than Angular.
Google trends also reports more searches for React worldwide.
The 2019 State of JavaScript report lists React as the most popular front-end framework, with
Angular being second to last, preceding only Ember. 71% of the participants said that they’ve
used React and would use it again. Only 21% of the participants said the same about Angular, and
35% said that they’ve used Angular and would not use it again (only 8% said that about React).
The Hacker News Hiring Trends for 2019 lists React as the most wanted technology amongst
employees for more than 31 months in a row.
Stack Overflow lists React as the second most popular framework after jQuery. Angular is listed
as the third one. Their Most Loved, Dreaded, and Wanted Web Frameworks report paints a
similar picture to the others.
The State of Developer Ecosystem 2020 report by Jet Brains confirms React’s position as the
most popular front-end framework.
Making a Decision
You might have already noted that each framework has its own set of capabilities, both with their
good and bad sides. But this analysis has been done outside of any particular context and thus
doesn’t provide an answer on which framework should you choose. To decide on that, you’ll need
to review it from the perspective of your project. This is something you’ll need to do on your own.
To get started, try answering these questions about your project and when you do, match the
answers against what you’ve learned about the two frameworks. This list might not be complete,
but should be enough to get you started:
If you’re starting a big project and you’d like to minimize the risk of making a bad choice, consider
creating a proof-of-concept product first. Pick some of the key features of the projects and try to
implement them in a simplistic manner using one of the frameworks. PoCs usually don’t take a lot
of time to build, but they’ll give you some valuable personal experience on working with the
framework and allow you to validate the key technical requirements. If you’re satisfied with the
results, you can continue with full-blown development. If not, failing fast will save you a lot of
headaches in the long run.
5
Getting Started
with React
Native
Wern Ancheta
With the ever-increasing popularity of smartphones, developers are looking into solutions for
building mobile applications. For developers with a web background, frameworks such as
Cordova and Ionic, React Native, NativeScript, and Flutter allow us to create mobile apps with
languages we’re already familiar with: HTML, XML, CSS, and JavaScript.
In this guide, we’ll take a closer look at React Native. You’ll learn the absolute basics of getting
started with it. Specifically, we’ll cover the following:
Prerequisites
This tutorial assumes that you’re coming from a web development background. The minimum
requirement for you to be able to confidently follow this tutorial is to know HTML, CSS, and
JavaScript. You should also know how to install software on your operating system and work with
the command line. We’ll also be using some ES6 syntax, so it would help if you know basic ES6
syntax as well. Knowledge of React is helpful but not required.
Another advantage of React Native is its ability to access native device features. There are many
plugins which you can use to access native device features, such as the camera and various
device sensors. If you’re in need of a platform-specific feature that hasn’t been implemented yet,
you can also build your own native modules—although that will require you to have considerable
knowledge of the native platform you want to support (Java or Kotlin for Android, and Objective C
or Swift for iOS).
If you’re coming here and you’re new to React, you might be wondering what it is. React is a
JavaScript library for the Web for building user interfaces. If you’re familiar with MVC, it’s
basically the View in MVC. React’s main purpose is to allow developers to build reusable UI
components. Examples of these components include buttons, sliders, and cards. React Native
took the idea of building reusable UI components and brought it into mobile app development.
What is Expo?
Before coming here, you might have heard of Expo. It’s even mentioned in the official React
Native docs, so you might be wondering what it is.
In simple terms, Expo allows you to build React Native apps without the initial headache that
comes with setting up your development environment. It only requires you to have Node
installed on your machine, and the Expo client app on your device or emulator.
But that’s just how Expo is initially sold. In reality, it’s much more than that. Expo is actually a
platform that gives you access to tools, libraries and services for building Android and iOS apps
faster with React Native. Expo comes with an SDK which includes most of the APIs you can ask
for in a mobile app development platform:
Camera
ImagePicker
Facebook
GoogleSignIn
Location
MapView
Permissions
Push Notifications
Video
Those are just few of the APIs you get access to out of the box if you start building React Native
apps with Expo. Of course, these APIs are available to you as well via native modules if you
develop your app using the standard React Native setup.
But as you begin to grasp the different concepts, and as the need for different native features
arises, you might find that Expo is kind of limiting. Yes, it has a lot of native features available, but
not all the native modules that are available to standard React Native projects are supported.
Projects like unimodules are beginning to close the gap between standard React
Native projects and Expo projects, as it allows developers to create native modules
that work for both React Native and ExpoKit.
The only prerequisite of setting up Expo is that you need to have Node.js installed in your
machine. To do this, you can either head to the official Node download page and grab the
relevant binaries for your system, or you can use a version manager, which allows you to install
multiple versions of Node and switch between them at will.
Once you have Node.js installed, install the Expo CLI. This is used for creating, serving, packaging,
and publishing projects:
That’s really all there is to it! The next step is to download the Expo client App for Android or iOS.
Note that this is the only way you can run Expo apps while you’re still in development. When
you’re ready to ship the app, you can follow this guide to create standalone binaries for iOS and
Android which can be submitted to the Apple App Store and Google Play Store.
On your terminal, execute the following command to create a new React Native project using
Expo:
Under Managed Workflow, select blank. By default, this will install the dependencies using Yarn.
You might be asking what this Managed workflow and Bare workflow is. These are the two
types of workflows that Expo supports. With a managed workflow, you only have to deal with
JavaScript and Expo manages everything for you. While in Bare workflow, you have full control
over the native code. It gives you the same freedom as the React Native CLI, but with the added
bonus of Expo’s libraries and services. You can visit this managed vs bare intro page if you want
to learn more about workflows in Expo.
Just like in a web environment, you can install libraries to easily implement different kinds of
functionality in React Native. Once the project is created, we need to install a couple of
dependencies: pokemon and axios. The former is used for verifying if the text entered in the
search box is a real Pokémon name, while axios is used to make an HTTP request to the API that
we’re using, namely the PokeAPI:
Before we proceed to coding, let’s first take a look at the directory structure of a React Native
project created with Expo:
Here’s a breakdown of the most important files and folders that you need to remember:
App.js : the main project file. This is where you’ll start developing your app. Any changes you
make to this file will be reflected on the screen.
src : acts as the main folder which stores all the source code related to the app itself. Note
that this isn’t included in the default project created by Expo CLI. The name of this folder can
be anything. Some people use app as well.
assets : this is where the app assets such as icons and splash screens are stored.
package.json : where the name and versions of the libraries you installed for this project are
added.
node_modules : where the libraries you installed are stored. Note that this already contains a
lot of folders before you installed the two libraries earlier. This is because React Native also
has its own dependencies. The same is true for all the other libraries you install.
Don’t mind the rest of the folders and files for now, as we won’t be needing them when just
getting started.
At this point, you can now run the app by executing the command below. Make sure that you’ve
already installed the corresponding Expo client (Android or iOS) for your phone and that it’s
connected to the same network as your computer before doing so. If you don’t have an Android
or iOS device you can test with, you can use the Android Studio Emulator or the iOS simulator so
you can run the app on your machine:
yarn start
2 Install it.
3 Link it. This is only necessary if you’re on Expo’s bare workflow and the package you’ve
Now that you’ve set up your environment and learned a bit about the workflow, we’re ready to
start coding the app.
First, let’s scaffold out the files we’ll need. These are src/Main.js , as well as src/components/
Pokemon.js . The Main component will hold the code to display the search input and query the
API, whereas the Pokemon component will be used to display the returned Pokémon data:
mkdir -p src/components
touch src/Main.js
touch src/components/Pokemon.js
// src/Main.js
import React, { Component } from 'react';
// src/components/Pokemon.js
import React from 'react';
Next, replace the contents of the App.js file with the following code:
function App() {
return <Main />;
}
The first line in the code above code imports React. You need to import this class any time you
want create a component.
The second line is where we import the custom Main component. We’ll fill this in later, but for
now, know that this is where we’ll put the majority of our code.
After that, we create the component by creating a new function. All this function does is return
the Main component.
Lastly, we export the class so that it can be imported and rendered by Expo.
// src/Main.js
import React, { Component } from 'react';
import {
SafeAreaView,
View,
Text,
TextInput,
Button,
Alert,
StyleSheet,
ActivityIndicator,
} from 'react-native';
The second line imports the components that are built into React Native. Here’s what each one
does:
SafeAreaView : for rendering content within the safe area boundaries of a device. This
automatically adds a padding that wraps its content so that it won’t be rendered on camera
notches and sensor housing area of a device.
View : a fundamental UI building block. This is mainly used as a wrapper for all the other
components so they’re structured in such a way that you can style them with ease. Think of it
as the equivalent of <div> . If you want to use Flexbox, you have to use this component.
Text : for displaying text.
TextInput : the UI component for inputting text. This text can be plain text, email, password,
or a number pad.
Button : for showing a platform-specific button. This component looks different based on the
platform it runs on. If it’s Android, it uses Material Design. If it’s iOS, it uses Cupertino.
Alert : for showing alerts and prompts.
ActivityIndicator : for showing a loading animation indicator.
StyleSheet : for defining the component styles.
As well as the custom Pokemon component used for displaying Pokémon data:
Resolving Components
If Expo is unable to resolve the Pokemon (or any other) component, try restarting the
server.
Because getting the required Pokémon data involves making two API requests, we have to set
the API’s base URL as a constant:
this.state = {
isLoading: false, // decides whether to show the activity indicator or not
searchInput: '', // the currently input text
name: '', // Pokémon name
pic: '', // Pokémon image URL
types: [], // Pokémon types array
desc: '', // Pokémon description
};
}
render() {
return null;
}
}
In the code above, we’re defining the main component of the app. You can do this by defining an
ES6 class and having it extend React’s Component class. This is another way of defining a
component in React. In the App.js file, we created a functional component. This time we’re
creating a class-based component.
The main difference between the two is that functional components are used for presentation
purposes only. Functional components have no need to keep their own state because all the data
they require is just passed to them via props. On the other hand, class-based components
maintain their own state and they’re usually the ones passing data to functional components.
Note that this is the traditional way of creating components in React. A more modern approach
would be to stick with a functional component and use the state hook to manage the
state—though in this tutorial we’re just going to keep things simple and stick with a class-based
component.
If you want to learn more about the difference between functional and class-based components,
read the tutorial “Functional vs Class-Components in React”.
Going back to the code, we’re initializing the state inside our component. You define it as a plain
JavaScript object. Any data that goes into the state should be responsible for changing what’s
rendered by the component. In this case, we put in isLoading to control the visibility of the
activity indicator and searchInput to keep track of the input value in the search box.
This is an important concept to remember. React Native’s built-in components, and even the
custom components you create, accept properties that control the following:
We’ll go through those properties in more detail in the next section. For now, know that the
values of those properties are usually updated through the state.
The rest of the state values are for the Pokémon data. It’s a good practice to set the initial value
with the same type of data you’re expecting to store later on—as this serves as documentation
as well.
Let’s return to the component class definition. When you extend React’s Component class, you
have to define a render() method. This contains the code for returning the component’s UI and
it’s made up of the React Native components we imported earlier.
Each component has its own set of props. These are basically attributes that you pass to the
component to control a specific aspect of it. In the code below, most of them have the style
prop, which is used to modify the styles of a component. You can pass any data type as a prop.
For example, the onChangeText prop of the TextInput is a function, while the types prop in the
Pokemon is an array of objects. Later on in the Pokemon component, you’ll see how the props will
be used.
render() {
const { name, pic, types, desc, searchInput, isLoading } = this.state; // extract the Pokémon data
return (
<SafeAreaView style={styles.wrapper}>
<View style={styles.container}>
<View style={styles.headContainer}>
<View style={styles.textInputContainer}>
<TextInput
style={styles.textInput}
onChangeText={(searchInput) => this.setState({ searchInput })}
value={this.state.searchInput}
placeholder="Search Pokémon"
/>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={this.searchPokemon}
title="Search"
color="#0064e1"
/>
</View>
</View>
<View style={styles.mainContainer}>
{isLoading && <ActivityIndicator size="large" color="#0064e1" />}
{!isLoading && (
<Pokemon name={name} pic={pic} types={types} desc={desc} />
)}
</View>
</View>
</SafeAreaView>
);
}
Breaking down the code above, we first extract the state data:
SafeAreaView.wrapper;
View.container;
View.headContainer;
View.textInputContainer;
TextInput;
View.buttonContainer;
Button;
View.mainContainer;
ActivityIndicator;
Pokemon;
The above structure is optimized for using Flexbox. Go ahead and define the component styles at
the bottom of the file:
In React Native, you define styles by using StyleSheet.create() and passing in the object that
contains your styles. These style definitions are basically JavaScript objects, and they follow the
same structure as your usual CSS styles:
element: {
property: value;
}
The wrapper and container is set to flex: 1 , which means it will occupy the entirety of the
available space because they have no siblings. React Native defaults to flexDirection:
'column' , which means it will lay out the flex items vertically.
In contrast, ( flexDirection: 'row' ) lays out items horizontally.
It’s different for headContainer , because even though it’s set to flex: 1 , it has mainContainer
as its sibling. This means that headContainer and mainContainer will both share the same
space. mainContainer is set to flex: 9 so it will occupy the majority of the available space
(around 90%), while headContainer will only occupy about 10%.
The rest of the styles are pretty self explanatory when you have a CSS background. Just
remember to omit - and set the following character to uppercase. For example, if you want to
set background-color , the React Native equivalent is backgroundColor .
Not all CSS properties that are available on the Web are supported in React Native. For
example, things like 3oats or table properties aren’t supported. You can 2nd the list of
supported CSS properties in the docs for View and Text components. Someone has
also compiled a React Native Styling Cheat Sheet, and there’s a style section in the
documentation for a speci2c React Native component that you want to use. For
example, here are the style properties that you can use for the Image component.
Let’s now break down the code for the TextInput and Button components. In this section, we’ll
talk about event handling, making HTTP requests, and updating the state in React Native.
<TextInput
style={styles.textInput}
onChangeText={(searchInput) => this.setState({ searchInput })}
value={this.state.searchInput}
placeholder="Search Pokémon"
/>
In the above code, we’re setting the function to execute when the user inputs something in the
component. Handling events like this are similar to how they’re handled in the DOM: you simply
pass the event name as a prop and set its value to the function you wish to execute. In this case,
we’re inlining it because we’re just updating the state. The value input by the user is automatically
passed as an argument to the function you supply, so all you have to do is update the state with
that value. Don’t forget to set the value of the TextInput to that of the state variable. Otherwise,
the value input by the user won’t show as they type.
Next, we move on to the Button component. Here, we’re listening for the onPress event:
Once pressed, the searchPokemon() function is executed. Add this function right below the
render() method. This function uses the async...await pattern because performing an HTTP
request is an asynchronous operation. You can also use Promises, but to keep our code concise,
we’ll stick with async/await instead. If you’re not familiar with this tecnique, be sure to read “Flow
Control in Modern JS”.
// src/Main.js
import React, { Component } from 'react';
...
export default class Main extends Component {
...
render() { ... }
this.setState({
isLoading: true, // show the loader while request is being performed
});
this.setState({
name,
pic: sprites.front_default,
types: this.getTypes(types),
desc: this.getDescription(flavor_text_entries),
isLoading: false, // hide loader
});
} catch (err) {
Alert.alert('Error', 'Pokémon not found');
}
};
}
Breaking down the code above, we first check if the entered Pokémon name is valid. If it’s valid,
the National Pokedex ID (if you open the link, that’s the number on top of the Pokémon name) is
returned and we supply it as a parameter for the HTTP request. The request is made using axios’
get() method, which corresponds to an HTTP GET request. Once the data is available, we
extract what we need and update the state.
Here’s the getTypes() function. All it does is reassign the slot and type properties of the
Pokémon types to id and name :
Here’s the getDescription() function. This finds the first English version of the flavor_text :
render() { ... }
Now that our app is fetching data from the API, it’s time to expand the Pokemon component we
stubbed out earlier, so that we can display said data. Open the src/components/Pokemon.js file
and replace the contents with the following:
return (
<View style={styles.mainDetails}>
<Image source={{ uri: pic }} style={styles.image} resizeMode="contain" />
<Text style={styles.mainText}>{name}</Text>
<FlatList
columnWrapperStyle={styles.types}
data={types}
numColumns={2}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={[styles[item.name], styles.type]}>
<Text style={styles.typeText}>{item.name}</Text>
</View>
)}
/>
<View style={styles.description}>
<Text>{desc}</Text>
</View>
</View>
);
};
//
const styles = StyleSheet.create({
mainDetails: {
padding: 30,
alignItems: 'center',
},
image: {
width: 100,
height: 100,
},
mainText: {
fontSize: 25,
fontWeight: 'bold',
textAlign: 'center',
},
description: {
marginTop: 20,
},
types: {
flexDirection: 'row',
marginTop: 20,
},
type: {
padding: 5,
width: 100,
alignItems: 'center',
},
typeText: {
color: '#fff',
},
normal: {
backgroundColor: '#8a8a59',
},
fire: {
backgroundColor: '#f08030',
},
water: {
backgroundColor: '#6890f0',
},
electric: {
backgroundColor: '#f8d030',
},
grass: {
backgroundColor: '#78c850',
},
ice: {
backgroundColor: '#98d8d8',
},
fighting: {
backgroundColor: '#c03028',
},
poison: {
backgroundColor: '#a040a0',
},
ground: {
backgroundColor: '#e0c068',
},
flying: {
backgroundColor: '#a890f0',
},
psychic: {
backgroundColor: '#f85888',
},
bug: {
backgroundColor: '#a8b820',
},
rock: {
backgroundColor: '#b8a038',
},
ghost: {
backgroundColor: '#705898',
},
dragon: {
backgroundColor: '#7038f8',
},
dark: {
backgroundColor: '#705848',
},
steel: {
backgroundColor: '#b8b8d0',
},
fairy: {
backgroundColor: '#e898e8',
},
});
In the code above, we first checked if the name has a falsy value. If it has, we simply return null ,
as there’s nothing to render.
Image : used for displaying images from the Internet or from the file system
FlatList : used for displaying lists
As we saw earlier, we’re passing in the Pokémon data as prop for this component. We can extract
those props the same way we extract individual properties from an object:
The Image component requires the source to be passed to it. The source can either be an
image from the file system, or, in this case, an image from the Internet. The former requires the
image to be included using require() , while the latter requires the image URL to be used as the
value of the uri property of the object you pass to it.
resizeMode allows you to control how the image will be resized based on its container. We used
contain , which means it will resize the image so that it fits within its container while still
maintaining its aspect ratio. Note that the container is the Image component itself. We’ve set its
width and height to 100 , so the image will be resized to those dimensions. If the original
image has a wider width than its height, a width of 100 will be used, while the height will
adjust accordingly to maintain the aspect ratio. If the original image dimension is smaller, it will
simply maintain its original size:
Next is the FlatList component. It’s used for rendering a list of items. In this case, we’re using it
to render the types of the Pokémon. This requires the data , which is an array containing the
items you want to render, and the renderItem , which is the function responsible for rendering
each item on the list. The item in the current iteration can be accessed the same way props are
accessed in a functional component:
<FlatList
columnWrapperStyle={styles.types}
data={types}
numColumns={2}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={[styles[item.name], styles.type]}>
<Text style={styles.typeText}>{item.name}</Text>
</View>
)}
/>
columnWrapperStyle : used for specifying the styles for each column. In this case, we want to
render each list item inline, so we’ve specified flexDirection: 'row' .
numColumns : the maximum number of columns you want to render for each row on the list. In
this case, we’ve specified 2 , because a Pokemon can only have two types at most.
keyExtractor : the function to use for extracting the keys for each item. You can actually omit
this one if you pass a key prop to the outer-most component of each of the list items.
At this point, you can now test the app on your device or emulator:
yarn start
While on the terminal, you can press a if you want to run the app on the Android emulator or i if
you want to run it on the iOS simulator.
Please also note that the names of the Pokémon must start with a capital letter—for example,
“Pikachu”, not “pikachu”.
And don’t forget, you can find the source code used in this tutorial on this GitHub repo.
Chapter
6
15 React
Interview
Questions with
Solutions
Nilson Jacques
React’s popularity shows no sign of waning, with the demand for developers still outstripping the
supply in many cities around the world. For less-experienced developers (or those who’ve been
out of the job market for a while), demonstrating your knowledge at the interview stage can be
daunting.
In this guide, we’ll look at fifteen questions covering a range of knowledge that’s central to
understanding and working effectively with React. For each question, I’ll summarize the answer
and give links to additional resources where you can find out more.
Answer
The virtual DOM is an in-memory representation of the actual HTML elements that make up your
application’s UI. When a component is re-rendered, the virtual DOM compares the changes to its
model of the DOM in order to create a list of updates to be applied. The main advantage is that
it’s highly efficient, only making the minimum necessary changes to the actual DOM, rather than
having to re-render large chunks.
Further reading
2. What’s JSX?
Answer
JSX is an extension to JavaScript syntax that allows for writing code that looks like HTML. It
compiles down to regular JavaScript function calls, providing a nicer way to create the markup
for your components.
Further reading
An introduction to JSX
JSX in Depth
Answer
Prior to React 16.8 (the introduction of hooks), class-based components were used to create
components that needed to maintain internal state, or utilize lifecycle methods (i.e.
componentDidMount and shouldComponentUpdate ). A class-based component is an ES6 class that
extends React’s Component class and, at minimum, implements a render() method.
Class component:
Functional components are stateless (again, < React 16.8) and return the output to be rendered.
They are preferred for rendering UI that only depends on props, as they’re simpler and more
performant than class-based components.
Functional component:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
The Introduction of Hooks
The introduction of hooks in React 16.8 means that these distinctions no longer apply
(see questions 14 and 15).
Further reading
Answer
When rendering out collections in React, adding a key to each repeated element is important to
help React track the association between elements and data. The key should be a unique ID,
ideally a UUID or other unique string from the collection item:
<ul>
{todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
)};
</ul>
Not using a key, or using an index as a key, can result in strange behavior when adding and
removing items from the collection.
Further reading
Answer
props are data that are passed into a component from its parent. They should not be mutated,
but rather only displayed or used to calculate other values. State is a component’s internal data
that can be modified during the lifetime of the component, and is maintained between re-
renders.
Further reading
props vs state
Answer
If you try to mutate a component’s state directly, React has no way of knowing that it needs to
re-render the component. By using the setState() method, React can update the component’s
UI.
Bonus
As a bonus, you can also talk about how state updates are not guaranteed to be synchronous. If
you need to update a component’s state based on another piece of state (or props), pass a
function to setState() that takes state and props as its two arguments:
Further reading
Answer
In order to type-check a component’s props, you can use the prop-types package (previously
included as part of React, prior to 15.5) to declare the type of value that’s expected and whether
the prop is required or not:
Greeting.propTypes = {
name: PropTypes.string
};
Further reading
Answer
Prop drilling is what happens when you need to pass data from a parent component down to a
component lower in the hierarchy, “drilling” through other components that have no need for the
props themselves other than to pass them on.
Sometimes prop drilling can be avoided by refactoring your components, avoiding prematurely
breaking out components into smaller ones, and keeping common state in the closest common
parent. Where you need to share state between components that are deep/far apart in your
component tree, you can use React’s Context API, or a dedicated state management library like
Redux.
Further reading
Prop Drilling
9. What’s React context?
Answer
The context API is provided by React to solve the issue of sharing state between multiple
components within an app. Before context was introduced, the only option was to bring in a
separate state management library, such as Redux. However, many developers feel that Redux
introduces a lot of unnecessary complexity, especially for smaller applications.
Further reading
Answer
Redux is a third-party state management library for React, created before the context API
existed. It’s based around the concept of a state container, called the store, that components can
receive data from as props. The only way to update the store is to dispatch an action to the store,
which is passed into a reducer. The reducer receives the action and the current state, and returns
a new state, triggering subscribed components to re-render.
Further reading
Answer
There are various approaches to styling React components, each with pros and cons. The main
ones to mention are:
Inline styling: great for prototyping, but has limitations (e.g. no styling of pseudo-classes)
Class-based CSS styles: more performant than inline styling, and familiar to developers new
to React
CSS-in-JS styling: there are a variety of libraries that allow for styles to be declared as
JavaScript within components, treating them more like code.
Further reading
Answer
In an HTML document, many form elements (e.g. <select> , <textarea> , <input> ) maintain
their own state. An uncontrolled component treats the DOM as the source of truth for the state
of these inputs. In a controlled component, the internal state is used to keep track of the element
value. When the value of the input changes, React re-renders the input.
Uncontrolled components can be useful when integrating with non-React code (e.g if you need
to support some kind of jQuery form plugin).
Further reading
Answer
Class-based components can declare special methods that are called at certain points in its
lifecycle, such as when it’s mounted (rendered into the DOM) and when it’s about to be
unmounted. These are useful for setting up and tearing down things a component might need,
setting up timers or binding to browser events, for example.
componentWillMount: called after the component is created, but before it’s rendered into
the DOM
componentDidMount: called after the first render; the component’s DOM element is now
available
componentWillReceiveProps: called when a prop updates
shouldComponentUpdate: when new props are received, this method can prevent a re-
render to optimize performance
componentWillUpdate: called when new props are received and shouldComponentUpdate
returns true
componentDidUpdate: called after the component has updated
componentWillUnmount: called before the component is removed from the DOM, allowing
you to clean up things like event listeners.
When dealing with functional components, the useEffect hook can be used to replicate
lifecycle behavior.
Further reading
Answer
Hooks are React’s attempt to bring the advantages of class-based components (i.e. internal state
and lifecycle methods) to functional components.
Further reading
Answer
Removing the need for class-based components, lifecycle hooks, and this keyword
shenanigans
Making it easier to reuse logic, by abstracting common functionality into custom hooks
More readable, testable code by being able to separate out logic from the components
themselves
Further reading
Wrapping Up
Although by no means a comprehensive list (React is constantly evolving), these questions cover
a lot of ground. Understanding these topics will give you a good working knowledge of the library,
along with some of its most recent changes. Following up with the suggested further reading will
help you cement your understanding, so you can demonstrate an in-depth knowledge.
Good luck!
Chapter
7
Five Awesome
React UI
Libraries for
Your Next
Project
Michael Wanyoike
In this guide, I’ll compare and contrast five popular UI libraries for React. I’ll look at their strengths
and weaknesses, as well as provide you with a runnable demo for each library, to give you a sense
of whether or not it would be a good fit for your next project.
If you’re new to human-centered design, you should watch this six minute “bad doors are
everywhere” Vox clip. It’s the best introduction on the subject I’ve come across. You’ll come to
understand that there’s an expectation about how we interact with physical and virtual objects.
Failing to observe these principles of design in your user interface will frustrate your users every
time they use your application.
Accessibility standards ensure that interfaces are usable by people with the widest range of
abilities possible. They encompass assistive technologies, such as screen readers, and they
ensure that text and graphic elements have the correct contrast ratio for good readability to
assist those with visual impairments. These standards are good for everyone: I’ve come across a
few sites with poor legibility even for users with 20/20 vision.
Fortunately for us front-end developers, we have access to open-source design systems and UI
libraries that have handled these exact concerns. All we have to do is install and use the provided
UI components based on the documentation and guidance given.
In order to use these UI libraries effectively, you’ll need to have some experience in using modern
CSS. Specifically, you should know how to work with either Flexbox or Grid layouts. Some of the
UI libraries we’ll look at in this article are not perfect, and you might need to leverage your CSS
skills to fix issues with layout styling.
When building interfaces with a UI library, your strategy should be to use the components like
Lego blocks. You may have to write some custom CSS to direct the layout of each component in
relation to the others, but you should avoid using plain CSS to change the internal styling of a
component. That is an uphill task. It’s much easier to build your own UI component from scratch.
Most UI library components are configurable via props that allow you to change attributes, such
as:
color presets
color schemes—such as dark, light, or inverted
size
direction
Some libraries do provide additional utilities for further component customization. Such utilities
usually target:
alignment
spacing
typography
display
As you can see, there is a learning curve involved if you want to be able to utilize a UI library
effectively. Picking an extensive UI library that you can use and rely on in multiple projects is
highly recommended, as you won’t waste time switching and re-learning a new UI library.
Currently, there are over 25 UI libraries made for React that are in various stages of development.
Most are free, but some require a commercial license. For this guide, we’ll focus on UI libraries
that are:
open-source
production-ready
regularly maintained
well documented
contain an extensive list of components
meet accessibility standards
In the upcoming sections, we’ll look at a handful of React UI libraries, starting with the simplest
and ending with some of the most advanced.
I’d also like to mention that, at the time of writing, React 17 had recently been released. You may
come across some migration issues with some of the projects. However, I believe they should be
resolved in the near future.
import 'bootstrap/dist/css/bootstrap.min.css';
You’ll find that React Strap provides React components for the majority of Bootstrap classes,
such as:
alerts
buttons
forms
carousels
navbars
tables (basic)
Shards React: a free, beautiful and modern React UI kit based on Shards (a Bootstrap 4 UI kit).
React Bootstrap: has better documentation and twice the number of GitHub stars. However, I
came across a bug using one of the components, which is why it wasn’t the main focus here.
React MDB Bootstrap: combines Bootstrap and Google’s Material Design. The free versions
are open-source under MIT License. The Pro versions are proprietary and can have an EULA
license. At the time of writing, the free version of this library hadn’t been updated for some
two months.
Bootstrap-based UI libraries are great for those who are already familiar with Bootstrap and want
to build a simple user interface. Otherwise, if you’re new to this, I’d recommend you look to other
UI libraries that offer more components.
Below, I’ve provided links for the documentation and source code:
Components Documentation
Source code: 9.6k GitHub stars
React Suite
React Suite, as the name suggests, is a library of React components for “middle platform and
back-end products”. It supports all modern browsers, as well as IE back to v10. Do note that the
IE 10 experience has been significantly downgraded with simpler styles and animations due to
the limitations of such a legacy browser.
Typescript
Electron
Reason
It supports theme customization and internationalization. React Suite uses Less as its styling
language, so you may need to install a Less compiler in your project.
React Suite provides developers with a massive list of advanced UI components, such as:
Layout
Loader
Placeholder
Popover, Tooltip, Alert, Notification
Badge
Drawer
Divider
TagPicker, SelectPicker, TreePicker, DatePicker
Cascader
Navbar
Sidenav
Steps
Very Advanced Table (virtualized)
Tree, CheckTree
Timeline
Full Calendar
Custom validation via Schema models
2 Update src/index.js :
import 'rsuite/dist/styles/rsuite-default.css';
or in src/styles.less :
@import '~rsuite/lib/styles/themes/default/index.less';
React Suite also provides a dark-theme version. All you have to do is swap out the current style
for this one in your src/styles.less :
@import '~rsuite/lib/styles/themes/dark/index.less';
Alternatively, you can programmatically allow users to switch between the two themes, light and
dark mode. Here is a quick mockup I created using the library.
Below I’ve provided links for the documentation and source code:
Documentation
Source: 4.8k GitHub stars
Ant Design
Ant Design refers to itself as a design language and framework. It features enterprise-class UI
components, internationalization support and theme customization. It requires a minimum React
version of 16.9 to operate and supports all modern browsers, as well as IE 11.
Advance table
Drawer
Popup over
Popup Messages
Confirmation Popups
Notification box
Toggle Switch
Double column transfer choice box
Tree Select
Upload interfaces
Full calendar
Skeleton
It also provides a wider color palette system containing a total of 120 colors, which is made up of
12 primary colors and their derivative colors.
Implementing Ant Design is your project is quite simple. All you have to do is:
import 'antd/dist/antd.css';
Documentation
Source: 68k GitHub stars
Material UI
Material Design is a comprehensive design specification created by Google in 2014. It’s
considered by many developers to be the gold standard for user interfaces, as it covers many
areas of design such as typography, grids, space, scale, color, and imagery. It’s also customizable
and supports dark mode, which is an essential requirement for many brands.
The best way to implement Google’s Material Design in your React project is to use Material UI.
Other implementations you can look at include MaterializeCSS and React MDB Bootstrap, which
is an amalgamation of Bootstrap and Material design. Material UI is more popular, and it features
a vast number of useful, advanced components, such as:
Snackbar
Progress
Speed dial
Stepper
Timeline
Datagrid
Do note that some components have pro versions of the basic ones. The pro versions are
commercial and often quite pricey, such as the advanced version of the Datagrid.
Implementing Material UI in your project is quite simple. All you have to do is:
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
function App() {
return <Button color="primary">Hello World</Button>;
}
Documentation
GitHub: 62K GitHub stars
Fluent UI React
Fluent UI is a design system by Microsoft that aims to provide a collection of UX components
that share code, design and behavior across multiple platforms. The platforms targeted are:
web
Windows
iOS
Android
Fluent UI React was formerly known as UI Fabric. Be aware that there is office-ui-fabric-react,
which refers to the same library we’ll be discussing here.
Implementing Fluent UI in your project is quite simple. All you have to do is:
function App() {
return <PrimaryButton>Hello World</PrimaryButton>;
}
I wasn’t able to completely dig into the library, as parts of the documentation were incomplete
and a number of components were throwing errors in the console. There are over 1,000 reported
issues on the main repository, but as the project is still in active development, we hope to see a
more polished version of this library soon from the company that brought us Visual Studio Code.
Documentation
GitHub: 9.7K GitHub stars
Bonus
Before we end this guide, I’d like us to consider a certain scenario. Let’s assume you have a UX
designer on your team and you’re in charge of the final look of the front-end interface. Most
probably, the design you’ll be given will be unique and original. Unfortunately, trying to implement
a custom UI design with an existing UI library can be very difficult.
An alternative approach is to use a utility-based CSS framework such as TailwindCSS. There are
already a few React TailwindCSS UI libraries that are available:
Tailwind React UI
Windmill React UI
Here's a demo using TailwindCSS, in order to demonstrate the flexibility of building custom UI
components from scratch.
This approach is good if there’s only a handful of components you have to build. However, if the
project requires a significant number of components, a better approach is for the UX designer to
use a Figma/Sketch design kit for the UI library you want to use. Here are a few examples:
Summary
The UI libraries I’ve discussed are some of the most popular on the market. If you need to get up
and running quickly, give your app an attractive look and feel, and ensure cross-browser and
cross-device compatibility, then any of them will serve you well.
However, as popular as these libraries are, they’re not the only players in town. There are many
great projects out there that I haven’t been able to cover here, such as Prime Faces React and
Blueprint.js, both of which deserve an honorable mention.
And if you’re charged with evaluating a React UI library, remember (at the very least) to check its:
maintenance/commit interval
documentation quality
list of UI components
Chapter
8
Getting Started
with Next.js
Craig Buckler
Next.js is a Node.js application framework created by Vercel. You can use it to create static
websites or blogs, but its scope is unlimited. Applications such as ecommerce stores, classified
advertising, social networks, APIs, and anything else should be possible.
I’m not convinced this helps! Most developers know React as a browser UI library and would be
forgiven for thinking Next.js is another client-side framework.
Next.js uses React to render pages and components—but it occurs server-side. Next.js is
primarily a Node.js server-side framework. It happens to use React, but that’s a fairly small part of
the overall developer experience.
When you initially access a Next.js-powered site, the server will return the page’s HTML with all
its assets (CSS, images, and so on). Where possible, page components will have been statically
generated at build time. The server can render other components at request time, so content can
be customized according to the user’s credentials or other criteria.
The response is fast because no client-side JavaScript processing has been required at this
point. Unlike a pure React app, Next.js pages are search-engine friendly and accessible to
everyone even when JavaScript fails.
If all goes well, the application effectively becomes an SPA after the initial page load. Links to
internal pages trigger an Ajax request which downloads the appropriate content, caches it, and
renders without a full-page refresh. Code-splitting and bundling techniques are used to ensure
the minimum of data is downloaded on demand.
Finally, when client-side processing is necessary, Next.js will have already returned a
component’s initial state from the server. That component is then hydrated so it’s fully
interactive in the browser.
The following features may tempt you to try Next.js for your next project …
Quick Setup and Zero Con5guration
Updating Node
To follow along with this tutorial, you’ll need a recent version of Node installed on your
PC. If this isn’t the case, head over to the Node home page and download the correct
binaries for your system. Alternatively, you can install Node using a version manager.
npx create-next-app
You can also create an app from scratch by initiating a new Node.js project and installing Next.js
and React modules:
mkdir myapp
cd myapp
npm init
npm i --save next react react-dom
A "scripts" section can then be added to your package.json file to start development and
build processes:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
Next.js uses webpack, Babel, TypeScript, Sass, CSS Modules, PostCSS, hot reloading and more,
but you shouldn’t require any configuration if you follow the conventions.
You can normally keep the server running; hot reloading ensures components and assets are
refreshed as you develop. If you don’t get the result you expect, it may be necessary to stop the
server with Ctrl|Cmd + C and restart again.
Open pages/index.js (or create it, if you installed the dependencies manually) and add the
following code. This exports a functional React component which returns JSX code:
Returning JSX
JSX must be returned within a single containing element such as a <div> . The <>
... </> notation de2nes a document fragment, so no additional container is required.
Your browser should automatically reload the page when the file is saved. You may also notice a
lightning icon at the bottom of the page, because Next.js has determined it can be pre-rendered
at build time.
Client-side Page Transitions
Standard HTML <a> tags used in JSX create a hyperlink to another page and the browser will
initiate a full-page refresh. Client-side transitions for pages within the same Next.js site can be
implemented using using the <Link> component from next/link . For example:
When the About us link is clicked, Next.js will request the page data using Ajax, cache it, and
render it within the page.
Dev Mode
This may be less evident when running in development mode, since pages are re-
rendered on demand.
Static Assets
Any file placed in the project’s public directory and sub-directories is presumed to be a static
asset such as an image, icon, robots.txt , or any other non-changing file. They can be
referenced using standard URLs. For example:
Template Components
Next.js uses React components to implement templating. You can place these anywhere, but a
new components directory is practical. For example, a <Layout> component could be defined in
components/layout.js :
import Link from 'next/link';
<footer>
<p><Link href="/terms">terms and conditions</Link></p>
</footer>
</>
);
}
Any page can use this component. Its content is passed to <Layout> in a children property of
the props object, such as pages/index.js :
Static Generation
Static generation occurs once at build time. Where possible, Next.js will generate static HTML
which requires no further processing on each request.
If you export an async function named getStaticProps() , Next.js will render the page at build
time using the props returned from that function. The following example at /pages/joke.js
calls the API at https://official-joke-api.appspot.com/jokes/random to fetch a random joke
(Next.js provides the node-fetch module):
return {
props: {
data: await res.json()
}
}
}
On a production server, the page rendered at http://localhost:3000/joke shows the same joke on
each refresh. (You may see different jokes during development, since static content can be re-
rendered.)
Server-side Rendering
Server-side rendering (SSR) occurs on every user request. This may be necessary if content
needs to change according to a user’s account settings, items in their shopping cart, their
geographical location, the browser they’re using, the time of day, or any other factor.
The getServerSideProps() function is identical to getStaticProps() , except that Next.js will call
it on every request. The function in the page above (in the Static Generation section) could be
renamed accordingly.
Calling a third-party API on every page request is not a good idea: there may be access
restrictions or performance issues. You could improve this by caching responses in a
2le or database so data is available locally.
Dynamic Routes
Adding [ square brackets ] to a page’s file name creates a dynamic route which calls the page
on any matching URL. For example, the file at pages/post/[id].js is called for routes such as
post/1 , post/abc , and so on:
Naming the file pages/post/[...id].js defines a catch-all route, which calls the page on routes
such as post/a/1 , posts/a/b/c , and so on. The returned id is an array containing the
associated paths—such as ['a', 'b', 'c'] .
If a page has dynamic routes and uses getStaticProps , it needs to define a list of paths to be
statically rendered at build time (see the Static Generation section above). This can be done by
exporting an async function named getStaticPaths() . For example, a file named [id].js
must have id values returned:
export async function getStaticPaths() {
return {
paths: [
{ params: { id: 'abc' } },
{ params: { id: 'xyz' } },
{ params: { id: '123' } }
],
fallback: false
};
}
False Fallback
Using a fallback value of false results in a 404 page for any unde2ned route.
The getStaticProps() function can be exported to return data for each id , where getData() is
called three times and passed 'abc' , 'xyz' , and '123' to return an object associated with
that id :
Client-side Rendering
Next.js will render React components on the server. However, any component using a hook such
as React.useState() or React.useEffect() will be hydrated as a client-side component after the
page has loaded. For example, this component at /components/clicker.js shows a button with a
number that increments on every click:
return (
<button onClick={() => setCount(count+1)}>
I was clicked { count } times
</button>
);
}
Be wary that some properties may be available on the server but not the client, and vice-versa.
For example, the following code will fail to render because the window object is not available
server-side:
To fix this issue, an initial state of null can be defined which is initialized within a useEffect
hook:
React.useEffect(() => {
if (!href) {
setHref(window.location.href);
}
}, [href])
This works because useEffect doesn’t run on the server, so by the time we hit that block, we
must be on the client.
API Routes
Any file inside the pages/api/ directory is mapped to an /api/ route and served as an API
endpoint rather than as a page.
You can either try this out in your browser, or by using cURL:
curl http://localhost:3000/api/hello
curl http://localhost:3000/api/hello\?name\=SitePoint
Like pages, APIs can also use dynamic route file notations. For example, pages/api/
user/[id].js is called when /api/user/123 is loaded. The '123' parameter can be determined
from req.query.id .
CSS Options
Next.js has built-in support for CSS options, including Styled JSX, CSS modules, Sass, Less, and
more.
Using the joke page at /pages/joke.js as an example, styled JSX can be added, which scopes
CSS styles to the component. In other words, the .setup and .punchline styles will not apply
elsewhere, even if the same selectors are used:
<style jsx>{`
.setup { font-weight: bold; }
.punchline { font-style: italic; }
`}</style>
</Layout>
);
}
Alternatively, CSS modules can be used by creating a file named jokes.module.css and
importing it as a styles object which references specific selectors:
Global CSS
Global CSS can be defined in a styles directory, such as styles/main.scss .
Using SCSS
To use SCSS 2les, install Sass with npm install sass 2rst.
Global stylesheets must be imported in a file named pages/_app.js so styles are applied to all
pages and components:
import '../styles/globals.css'
The Next.js server can be started on any production server with Node.js v10 or above using npm
run start or npx next start .
Vercel offers automated deployment and hosting options for Next.js apps.
The resulting HTML and asset files are output to an out directory, which can be copied to any
web server directory.
9
React vs Vue: A
Side-by-side
Comparison
Michael Wanyoike
“Should I learn React or Vue?” is a question many developers can struggle with when starting out
in front-end development. Back in the day, React was a solid choice, as it didn’t have a strong
competitor (other than maybe AngularJS). However, Vue has grown rapidly these last few years,
and has now become a serious contender for building apps of all sizes.
I’ve been using React in multiple projects for the past couple of years and I love it. However,
recently I’ve also had the chance to get to grips with Vue. In this guide, I want to look at how the
two stack up against each other and hopefully provide a starting point for those who have to
decide which way to jump.
But before making a decision, let’s first ask ourselves why we’re asking this question. What is it
that we’re really looking for in a front-end framework?
is easy to learn
has excellent documentation
provides developer support through forums, Slack, Discord channels etc.
allows easy integration with other platforms
is stable and regularly maintained
offers new job opportunities
Before we move on, you may be wondering why I haven’t included Angular in this comparison. In
my experience, Angular is the hardest JavaScript framework to learn. I’ve also found that most
releases have a number of significant breaking changes that make the majority of past
documentation and tutorials outdated, even if they were only published in the last year.
Upgrading your Angular projects to the latest major release can also be a time consuming
process, as you have to re-write certain sections of your code to comply with the new
requirements. You’ll also need a solid test suite to ensure all the features you had implemented
are still working after the migration.
With that out of the way, let’s dive in to the core of our comparison of React and Vue.
A High-level Overview of React vs Vue
React is a view library with hardly any opinion on how you should structure your code. Vue, on the
other hand, is a framework made up of core libraries and software patterns. Both are designed to
help developers build user interfaces.
If you want a quick answer to which front-end framework to go with, I’ll tell you right now: if
you’re looking for a job, go with React. If you’re looking to build your own software product or
business, go with Vue.
Feel free to stop right here. By making a fast decision for yourself, you won’t deal with the fatigue
from struggling to make a choice later on. But if you’re not sure which is the best fit for you, or
you just want to see what things look like on the other side of the fence, keep reading.
Although I’ll try to remain unbiased and objective throughout this guide, let me tell you what got
me enthusiastic about Vue.
Recently, I migrated a project that was still in development from a React framework (Next.js), to a
Vue framework (Nuxt.js). Making the switch was like a breath of fresh air. Many of the issues I had
been struggling with were gone in an instant. For example:
Next.js lacks a modular/plugin ecosystem. Hence integration with a platform or a library such
as TailwindCSS is manual. With Nuxt, all you have do is install a plugin, and the integration
works with very minimal configuration.
Next.js is a framework that gives you a bare-bones project structure. You have to research
and set up additional tools inside your project workspace to ensure formatting, linting and line
endings are consistent in each code file. With Nuxt.js, you’re given the option to install all
these additional tools and configurations during the project creation stage.
Next uses .js files for everything, including library and React code. This means if you enable
linting of React on .js files, you’ll get a lot of false positives on utility JavaScript files that
don’t contain any React code. With Nuxt, it uses a .vue extension, which has its own linting
rules.
None of these issues were real show stoppers, and had more to do with the frameworks
themselves than with React or Vue. But nonetheless, this was my entry ticket to the Vue
ecosystem.
And please don’t think I’m implying that React is a terrible framework. It isn’t. React took us from
a terrible, buggy front-end environment to a much better one. Vue takes us even further to a
better, more efficient development workflow. It’s still early days, but that has been the main
difference I’ve encountered when working with React and Vue.
Ease of Use
While working with Vue code, you always have the documentation on hand that explains the
software pattern and practice you should use to solve a particular problem. Sometimes I feel like
the creators of Vue are reading my mind whenever they have a well documented solution to a
problem I just encountered.
With React, you’re provided the tools without clear instructions on how you should use them.
Hence, you have to research, reading tutorials and articles on how to solve a particular problem
using React. Quite often, you’ll have to install additional libraries to solve certain problems.
A good example of such a problem I solved instantly in Vue was when I was trying to figure out
how to toggle a class name programmatically. I simply searched for “Vue dynamic class” and
straight away found this page, which explained exactly how to do it. All I had to do was simply use
the :class attribute.
With React, after you Google the search term, you’ll have to go through Stack Overflow and a few
more articles. Eventually you’ll come across the classnames package, which you have to install
and import into your React file to get the equivalent feature of Vue’s :class attribute.
With Vue, you’ll find that the core library provides the majority of the common features required
in any project. So you won’t need as many third-party packages to implement a feature.
Both React and Vue are excellent in terms of backward compatibility. 99% of the time, upgrading
an older React project goes smoothly without any issues. I haven’t used Vue for very long, so I
can’t yet say the same about Vue. The Vue team has just released their latest major release—Vue
3—which has been in the making for a long time. It’s a rewrite of Vue 2 that’s taken advantage of
new JavaScript language features and also addressed architectural issues in the current
codebase.
The latest major release of Vue has successfully been implemented in a way that doesn’t inflict
huge migration costs to users—which would also cause fragmentation in the ecosystem. Here’s a
migration guide where they’ve listed their breaking changes. As a new Vue developer, I haven’t
been affected at all and am quite happy to benefit from all the improvements and changes
they’ve introduced in Vue 3.
Coding Comparison
React is about a year older than Vue. It brought significant and disruptive changes to front-end
web development, pushing predecessors like jQuery towards obsolescence. As a result, it has
the largest user base. Vue, on the other hand, has a much smaller community that’s been slowly
growing over time. Though smaller, the community is still sufficient, and you can quickly get
support from its members.
When it comes to performance, both React and Vue are very fast and pretty much on the same
level. Vue 3’s architecture has been re-written for improved performance. There’s a third-party
benchmark you can view to compare performance results. Unfortunately, these results are for
older versions of React and Vue. Still, the results were quite good back then and most definitely
they should have improved in the most recent versions.
Let’s now get to the developer experience differences between React and Vue. When it comes
to local state management and lifecycle methods, both are on par. But I do prefer Vue’s naming
convention of lifecycle methods—for example, React’s componentWillUnmount() vs Vue’s
beforeUnmount() . However, that’s a minor issue, and there’s a number of situations where I feel
Vue is superior.
React requires the use of JSX to render HTML content. JSX is a syntax that allows you to mix
JavaScript and HTML elements. There are many developers who love this style. However, there
are limitations, which I’ll cover shortly. Here’s a JSX component example:
Vue does support JSX, but I prefer the classic HTML syntax. Here’s a Vue template component
example:
<template>
<div class="py-4 bg-red-100 border border-red-200">
<p class="italic text-center text-red-700">
Hello, {{ name }}
</p>
</div>
</template>
export default {
props: ['name']
}
To me, the separation of HTML and JavaScript code is preferble. It’s much cleaner. Novice Vue
developers can leverage their existing HTML skills without having to learn anything new. With
JSX, you’ll have to rename reserved keywords such as class to className , which is something I
often forget. In Vue, it’s much easier to copy HTML code from theme templates and design kits
and use it as is. React devs have to put in a little more work while copying HTML code to JSX.
Fortunately for them, there are several React theme templates with JSX syntax on the market.
CSS scoping ensures the styles you implement in a component don’t affect the rest of the
application. There are many ways you can implement CSS scoping in both React and Vue. You
can import a component CSS file or use inline styling. You can also put your component styles in
the global style sheet and use the BEM naming convention to provide scoping.
Vue supports scoped styling right inside the component. And it looks like this:
<template>
<div class="hero">
<h1> Hello World </h1>
</div>
</template>
<style scoped>
.hero {
@ apply bg-gray-900 text-gray-100 text-4xl;
}
</style>
With Vue, you can use the @apply directive to inline any existing utility classes into your own
custom CSS—something that’s quite handy when using a CSS framework like TailWindCSS. This
isn’t possible in React unless you implement it in an external stylesheet. There are CSS libraries
such as styled components and emotion that make styling in React more manageable. I’ve tried
using them, but I’m not convinced of their benefits. However, that’s just me, as there are many
React and Vue developers who love using them.
Conditional Rendering
Conditional rendering is basically an if-statement for HTML code. There’s a couple of ways you
can do it in React.
With the inline approach, I find it a bit hard to read the code. This is how Vue handles conditional
rendering:
<template>
<div>
<h1>Hello!</h1>
<h2 v-if="unreadMessages.length > 0">
You have {{ unreadMessages.length }} unread messages.
</h2>
</div>
</template>
To me, the Vue version is more readable. You can also add an “else” block using v-else like this:
<template>
<div>
<h1>Hello!</h1>
<h2 v-if="unreadMessages.length > 0">
You have {{ unreadMessages.length }} unread messages.
</h2>
<h2 v-else>You have read all your messages</h2>
</div>
</template>
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn
? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} />
}
</div>
);
}
As you can see, it’s not quite obvious what’s going on here. With Vue, you can use v-else-if to
stack multiple conditions like this:
<template>
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</template>
Vue also provides a v-show directive that’s preferred if you need to toggle something very often.
v-if is recommended if the condition is unlikely to change at runtime.
List Rendering
To render lists in React, you’ll need to use the JavaScript map() function to generate an HTML
element for each item. Here’s an example of how that might look:
render() {
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number, index) => <li key={index}>{number}</li>);
return (
<div>
<ul>{listItems}</ul>
</div>
);
}
Keys are required to uniquely identify each element in order for React to track which items have
changed, been added or removed. This requirement also applies to Vue. However, Vue uses
directives to perform list rendering like this:
<template>
<div>
<ul v-for="(number, index) in numbers" :key={index}>
<li>{{ number }}</li>
</ul>
</div>
</template>
I strongly prefer the way Vue handles list rendering. In this simple example, you won’t see much
of a difference. However, the difference will become clearer when the code starts to become
bigger. With React, you have to keep looking up and down to see how the code works. With the
Vue code, you can read continuously from top to bottom and quickly understand the code
without having to refer back up again.
The latest trend for ecommerce businesses is to replace the front end with a static website built
with a static-site generator. Static websites are blazing fast and greatly improve the online
shopping experience for visitors. Businesses that fail to catch on will soon have their “Kodak
moment”. The main benefits of static-site generation include:
To implement this kind of functionality in React and Vue, it makes sense to turn to an existing
framework such as Gatsby (for React) and Gridsome (for Vue).
Both of these are well suited to static-site generation for ecommerce applications due to a
feature called hydration. This is a process of shipping HTML to a browser, then when JavaScript
can run, converting this HTML into a single-page application to make it interactive. This is an
extremely useful feature that is not natively possible with static-site generators such as Hugo.
They both also provide native support for GraphQL, which greatly simplifies the task of querying
data from back-end providers.
Speaking of back-end providers, we need to ensure that the framework we choose can easily
connect to the back end of our choice. The back ends you’ll likely consider are:
You’ll also need to consider essential ecommerce services, which can be implemented by
integrating with platforms that provide:
If you were building a blog, you would consider a different set of platforms to integrate with, such
as Disqus for comments. I hope you get my point on the evaluation strategy I’m trying to drive at.
Once you’ve identified all the systems and features you need to work with, go through the
documentation of each platform and evaluate the level of support they provide for each
framework. Fortunately, you’ll find either an official plugin or a community one that allows fast
and easy integration with a particular platform/service.
Project Breakdown
I’ve built two identical headphone ecommerce projects each with a different framework:
Gatsby — React
Gridsome — Vue
Both projects have access to the same back end that I’ve built and populated using Storyblok, a
headless CMS service. I’ve also used TailwindCSS, a utility-based CSS framework, in both
frameworks.
Here’s a screenshot of the Gridsome version. The Gatsby version looks identical:
The source code for the Gatsby version is here, and you can find the Gridsome source code here.
I’ve included my (read-only) Storyblok token in the repo, so you should be able to clone either
repository, install the dependencies and have the complete site run on your machine. I
recommend that you take some time to explore the source code and get a feel for how React and
Vue do things.
Both Gatsby and Gridsome can be used as static-site generators. They have the same
architecture and share the same concepts. Gatsby was the first to launch, and it uses React.
Unlike other static-site generators that run on non-JavaScript languages, Gatsby provides
developers with the unique hydration feature. As explained above, this means that, when a static
page is loaded on the browser from the server, React takes over and starts handling rendering of
the page. Thus it becomes a single-page application, but with fast initial load times and SEO
support.
Gridsome is the Vue alternative to Gatsby. It’s highly inspired by Gatsby, and as you’ll see, the
architecture and concepts are identical. These include:
performance optimization using Google’s PRPL pattern
automatic routing
a plugin ecosystem
simple integration with data from different sources such as file system, CMS, APIs, SaaS
platforms and databases
a GraphQL data layer
PWA support
Both Gridsome and Gatsby have a plugin that supports easy integration with Storyblok source
via the GraphQL layer:
gridsome-source-storyblok
gatsby-source-storyblok
The plugins are well documented, with clear instructions on how to use them. Storyblok also
provides first-class documentation and technical support to both site generators. They also have
excellent GraphQL interfaces with excellent documentation.
Gridsome GraphQL:
Gatsby GraphQL:
Configuring the Secret API Token
In order to connect to Storyblok, you need to provide an API token that’s made available via the
settings dashboard. It’s important that this API token is not saved in your source code. The
recommended place to keep is in a .env file. This file needs to be excluded using .gitignore .
Here’s an example in Gridsome of how the token is accessed in gridsome-config.js :
{
plugins: [
{
use: 'gridsome-source-storyblok',
options: {
client: {
accessToken: process.env.STORYBLOK_API,
},
},
},
{
use: 'gridsome-plugin-tailwindcss',
},
],
}
Quite simple, right? You probably should expect that it’s the same process with Gatsby, but,
unfortunately, no. It’s an unusually long process. The technical reason why it can’t be done the
simple way is beyond me. Thanks to Storyblok’s technical support, I was guided on how to set it
up. This is the process.
At the top of gatsby-node.js, add this code to suppress the fs error messages that crop up
when using a dotenv package:
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
})
You’ll need to store your API token in the .env.development file. Make sure to exclude it in your
.gitignore file. Next, you’ll have to access the API token in gatsby-config.js as follows:
{
plugins: [
{
resolve: 'gatsby-source-storyblok',
options: {
accessToken: `${process.env.STORYBLOK_TOKEN}`,
homeSlug: 'home',
version: process.env.NODE_ENV === 'production' ? 'published' : 'draft',
},
},
]
}
Take note of the tilde syntax used to wrap process.env.STORYBLOK_TOKEN . Finally, you’ll need to
modify your develop script in package.json . In Linux, you don’t need cross-env , but it’s
important to use it since it’s needed on Windows:
{
"scripts": {
"develop": "cross-env NODE_ENV=development && gatsby develop"
}
}
With all that set, Gatsby should connect to your Storyblok API safely via the secret .env token.
It took me two days to resolve this. If you were to follow this Stack Overflow answer, you’d be
stuck like I was. There are quite a number of dead-end answers online regarding this topic. I’m
quite grateful to Storyblok’s support team for helping me resolve this issue.
Luckily for you, I’ve saved you hours of pain, as I’ve documented the whole procedure for you.
Both frameworks are excellent at achieving very high Chrome Lighthouse scores with zero
effort. For a monolithic CMS such as WordPress, achieving good scores is extremely hard even
with the best caching plugins and hosting. With the headphone projects I’ve built, both scored
100% on the desktop page speed test. For mobile, the Gridsome version got 91% while the
Gatsby version got 97%.
Image Optimization
Image optimization for today’s computing devices is important! In the past, smartphones used to
have lower screen resolutions, so you only needed to provide a lower resolution image.
Nowadays, most smartphones—even entry level ones—have high resolution screens that are
capable of showing detailed images.
There are also no standards on the size of screen resolution being used on different devices.
Trying to support them all is near impossible and impractical. The best solution is to generate
multiple resolutions of the same image and let the browser select the optimum image resolution
for its screen. This is done using the srcset attribute of the img tag.
With Gatsby, this work is done for you by gatsby-image. Gridsome’s version is called g-image.
In both versions, I used Storyblok’s image optimization service to optimize the product images.
Both Gatsby and Gridsome have internal tools for image optimization which, due to lack of time, I
wasn’t able to use.
In Gatsby’s case, I should have used gatsby-storyblok-image, a plugin that allows use of gatsby-
image outside of GraphQL. I believe if I had completed that step, I’d have achieved 100% mobile
page speed for Gatsby.
In Gridsome’s case, there’s unfortunately no similar plugin. The g-image component (see below)
only optimizes images loaded from the file system. Fortunately, the gridsome-source-storyblok
allows downloading of images to the local file system. It also updates content references to
reflect the new location of the images. If I’d set this up, I believe I’d have achieved a higher score
in the Gridsome page speed test.
If I were to choose a winner here, I’d say Gatsby has better image optimization support for
Storyblok.
The Gatsby project node_modules folder consumed about 464MB of disk space. It relies on quite
a number of dependencies for it to work:
{
"dependencies": {
"tailwindcss": "^1.9.4",
"@tailwindcss/typography": "^0.2.0",
"gatsby": "^2.24.67",
"gatsby-env-variables": "^2.0.0",
"gatsby-image": "^2.4.20",
"gatsby-plugin-manifest": "^2.4.33",
"gatsby-plugin-offline": "^3.2.30",
"gatsby-plugin-postcss": "^3.0.3",
"gatsby-plugin-react-helmet": "^3.3.12",
"gatsby-plugin-sharp": "^2.6.38",
"gatsby-source-filesystem": "^2.3.32",
"gatsby-source-storyblok": "^1.1.1",
"gatsby-transformer-sharp": "^2.5.16",
"postcss": "^8.1.2",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "^6.1.0",
"react-icons": "^3.11.0",
"storyblok-react": "^0.1.1",
"storyblok-rich-text-react-renderer": "^2.0.0"
},
"devDependencies": {
"cross-env": "^7.0.2",
"dotenv": "^8.2.0",
"prettier": "2.1.2",
},
}
Gridsome, on the hand, only consumed 256 MB of node_modules space—about half. As a result,
running the dev server for Gridsome was faster, especially on my 5400 rpm hard drive. Its
package dependencies are surprisingly small:
{
"dependencies": {
"gridsome": "^0.7.0",
"gridsome-source-storyblok": "^1.1.0",
"gridsome-plugin-tailwindcss": "^3.0.1",
"@tailwindcss/typography": "^0.2.0",
"vue-awesome": "^4.1.0"
},
"devDependencies": {
"prettier": "^2.1.2"
}
}
I must say it’s incredible how one can built an identical site in Gridsome with half the
dependencies.
Query Syntax
GraphQL page queries are used to generate pages. However, sometimes we need to make a
component fetch its own data. For that, we need to use static queries. Below is a simplified
version of the ProductsList.jsx component:
return (
<div className="container mx-auto mt-2">
<div className="flex flex-wrap justify-center px-4 mt-4 md:justify-between">
{productCards}
</div>
</div>
)
}
With Gatsby, there’s the useStaticQuery hook used to write the GraphQL code. Let’s have a look
at the Gridsome version—ProductsList.vue—below:
<template>
<div class="container mx-auto mt-2">
<div class="flex flex-wrap justify-center px-4 mt-4 md:justify-between">
<div v-for="product in sortedProducts" :key="product.id">
<ProductCard :product="product" />
</div>
</div>
</div>
</template>
<static-query>
query {
products: allStoryblokEntry(sortBy: "created_at", filter: {full_slug: {regex:"products" }}) {
totalCount
edges{
node {
id
name
full_slug
content
created_at
}
}
}
}
</static-query>
<script>
import ProductCard from './ProductCard'
export default {
components: {
ProductCard,
},
data() {
return {
products: null,
}
},
created() {
// Extract content & edge data into products
this.products = this.$static.products.edges.map((edge) => {
return edge.node.content
})
},
}
</script>
What you’ll notice is that the Gridsome version uses the <static-query> tag to separate
GraphQL code from the JavaScript section. I prefer this version, since you can have clean,
readable code with separate sections for HTML, JavaScript, GraphQL and CSS.
With Gatsby projects, you can easily come across code that’s a mix of all four in one code block,
which can be messy and unreadable.
Component Management
Modern headless CMSs such as Prismic and Storyblok use custom components to organize and
structure content. A full-blown website can easily have 100 components for rendering different
types of content.
Vue provides us with a feature known as dynamic components to help manage component code.
This feature allows the switching of components during runtime depending on the content
provided. Here’s an example of how I’ve used it in Gridsome:
<template>
<Layout>
<component
v-if="story.content.component"
:key="story.content._uid"
:blok="story.content"
:is="story.content.component"
/>
</Layout>
</template>
In React, there’s no equivalent feature, so you have to implement the above solution using classic
JavaScript code like this:
const ComponentList = {
page: Page,
hero: Hero,
'product-list': ProductList,
product: Product,
'page-content': PageContent,
placeholder: Placeholder,
}
With React, you need to import each new content component you create. The code works, but
you’ll have more code to maintain as your project grows.
I think it’s fair to say that Gatsby takes the cake here, as it’s way more popular (it recently raised
$28 million in funding, for example). There are some Gridsome opportunities you can find on
freelancer sites, although in my experience, Nuxt is more popular and has plenty of contract job
opportunities.
Other than that, at the time of writing, a quick search on indeed.com reveals almost 4,000
positions working with Vue, compared to 55,000+ positions listed for React developers. So
basically, if you’re a developer looking for job opportunities, it’s better to focus on React and
integration with other platforms.
However, if you’re a developer looking to start your own project, a Vue framework is a better fit,
since you can implement new features at a fast pace. Plus, in my experience, you’ll find that there
are more Vue developers than there are Vue jobs available. A React developer can also start
working on a Vue project within just a few hours of reading Vue’s documentation.
Summary
If you were tasked with migrating an existing site with thousands of posts, my recommendation
is to go with Gatsby. Gatsby is the only JavaScript static-site generator that supports incremental
builds. This feature is available via Gatsby Cloud, which requires a subscription. Incremental
builds are suitable if you have multiple authors publishing content multiple times a day. Gatsby
also has a better approach to image optimization when it comes to integrating it with the
Storyblok image optimization service.
Gridsome, on the other hand, is better for starting projects from scratch where the requirements
are not fully known. Gridsome allows you to implement new features fast, as it’s well
documented on software patterns and has a rich plugin ecosystem as well. It supports a cached
build for faster generation, but it’s not as fast as incremental builds. The incremental build
feature is currently planned on Gridsome’s roadmap.
As for whether React or Vue is a better fit for your next project, that’s for you to decide. But I
hope I’ve provided you with plenty of jumping off points to base your decision on.