Skip to main content

Lesson 12 - React 3: Styling and Libraries/Global State/Deployment

Introduction

Welcome to the course's 3rd and final react lesson. In the previous lesson, you were introduced to key parts of the React ecosystem in the form of package managers, routing, and axios. In this lesson, we'll continue delving into the react ecosystem, the frontend ecosystem as a whole, and talk about some general software development principles as well.

We'll start by introducing how styling works in React, covering a couple ways that you can use to ensure that your React apps look as beautiful as your websites did in the first part of the course.

Next, we'll dive into the notion of libraries in React and the powerful ecosystem that surrounds it. From there, we'll cover component libraries, a powerful way to write less code and create stunning UI's in minutes as compared to hours.

We'll then introduce basic architecture and file design principles to help delineate efficient organization practices and gear everyone up for how to structure a large front-end project.

Lastly, we'll touch upon a number of more advanced frontend technologies such as Server-Side Rendering (SSR), Typescript, and Redux. We won't be going in-depth into these technologies, but we feel like they're good to know about at a surface level at the very least. Once you know what these technologies mean you'll be able to keep up with conversations about frontend technologies, as well as have a couple of points to dive deeper into frontend technologies after we finish the react section of the course's frontend curriculum.

Styling in React

There are many, many ways to style your components and JSX code in React. In this reading we'll talk about Tailwind CSS with Vivid, CSS-in-JS, CSS Modules, and Styled Components.

Tailwind CSS

Tailwind CSS is a utility-first CSS framework. This means that instead of writing traditional global CSS like background-color: #f63344, you apply styles in-line via small “utility classes” like p-4 for padding or bg-red-500 for a red background.

Each of these utility classes is atomic, so they only apply one style rule at a time. While you can use them to write arbitrary CSS using their arbitrary notation (e.g., bg-[#f63344]), most of the time you’ll be using the color and sizing scales that Tailwind provides for you. All of these features can also be easily configured be changing your tailwind.config.js.

Why Use Tailwind

Tailwind offers benefits for beginners and experts alike!

For beginners or simple applications, Tailwind is a fast way to write all your styling inline. By not having to deal with the abstraction of component-based classnames or fine-tuning colors and pixel values, you can move faster with Tailwind than with alternative CSS frameworks.

For more advanced use-cases, Tailwind forms a useful part of a design system by streamlining modularity and reducing unneeded abstractions. Since Tailwind lets you configure a set of common sizes, colors, and utilities, you can easily write consistent styling across your app. By removing modularity at the CSS level (since styling is done inline), you can focus on just making your React code modular.

To prevent long class strings at all levels of your code, you generally have to be more thoughtful about your component modularity when using Tailwind CSS.

Installation

The official Tailwind installation guide does a great job of walking you through the easy 4 step setup. You can follow the “PostCSS” or “Framework Guides” sections there to get started.

Usage

Once Tailwind is set up, you can use any of the classes in their docs right in your code:

<h1 class="text-3xl font-bold underline">
Hello world!
</h1>

This snippet makes your heading large, bolded, and underlined — pretty self-explanatory!

Vivid

Vivid is an in-browser visual editor that lets you test out Tailwind styles and automatically write them directly to your code.

With Vivid, you can click on any component in your page and have its code pop up right in your browser. From there, you can edit its code in the code pane, or preview and apply styles with shortcuts through the command palette.

Installation

To summarize the Vivid docs:

  1. Install Vivid with npm i -D vivid-studio
  2. Initialize it by pasting the following code at the top of your root file outside of any functions:
if (
typeof window !== "undefined" &&
process.env.NODE_ENV === "development"
) {
import("vivid-studio").then((v) => v.run());
import("vivid-studio/style.css");
}

Usage

Once Vivid is set up, you just have to start your app in development mode (usually with npm run start or npm run dev). From there, Vivid will walk you through its functionality!

Instead of the usual loop of opening your IDE, looking for a component’s code, and testing out styles in the browser, you can just Cmd-Click (Windows/Linux: Ctrl-Click) any part of your page and start editing its code from your browser.

Once you get comfortable with editing code in the code pane, you can iterate through styles even faster with the command palette shortcuts Vivid provides (Cmd/Ctrl + K).

Vivid Demo

CSS-in-JS

CSS-in-JS is a term you'll hear often, but what exactly does it mean? CSS-in-JS usually means using an alternative method of styling than just plain CSS files, such as styled-components or css-modules. These solutions often require some change in the javascript that is being written, which is why we call these solutions "CSS in JS".

Why do we care about using CSS-in-JS? This is because all CSS in our react app is global. Say you have two components, Page1 and Page2. Even if you create page1.css and page2.css and only import page1.css into your Page1 component, all the classes you create in page1.css will apply to your Page2 component as well. Thus if you accidentally use the same class name across both components, or use a class name multiple times anywhere in your app, the CSS rules you've written in page1.css will apply everywhere, which in most cases is highly undesirable and can cause unintended and difficult to fix CSS collisions.

CSS Modules

CSS modules transforms your CSS files from being globally scoped to being component scoped, which means that the CSS you import into your component only affects the component you've imported that CSS file into. To transform a CSS file into a CSS modules file, simply change the file name from <file name>.css to <file name>.module.css. CSS modules also works with sass. In order to use CSS modules in your app, make the following changes.

//Importing Regular CSS
import './styles.css';

//Using Regular CSS
<div className="container">
<h3>Hi There!</h3>
</div>;
//Importing CSS Modules
import styles from './styles.module.css';

//Using CSS Modules
<div className={styles['container']}>
<h3>Hi There!</h3>
</div>;

The difference in your JavaScript files is that you treat your CSS file as an object and access the class names the same way you would access an object's attributes, but that's it! Your CSS files remain the same and now there's no need to worry about annoying CSS collisions.

Installation

CSS modules comes pre-installed with Create React App (sometimes referred to as CRA).

Documentation

Documentation


Styled Components

Using styled components is a bit more tricky.

Why Use Styled Components

  • Write CSS in JS alongside HTML in JS, but don't have to inline the CSS
  • Keeps track of which components are rendered on a page and injects their styles and nothing else, fully automatically.
  • You never have to worry about duplication, overlap or misspellings. No need to keep track of class names.
  • Adapting the styling of a component based on its props or a global theme is simple and intuitive without having to manually manage dozens of classes.

Installation

npm i styled-components

Trying It Out

In app.js,

const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;

const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;

render(
<Wrapper>
<Title>Hello World!</Title>
</Wrapper>
);

The naming is as intuitive as it seems — Title is an <h1> tag, but with some styles associated with it. Wrapper is a div, but with some styles associated with it. To add style, we no longer need to inline, we can simply change the definition of Title or Wrapper.

Passing Arguments

const Button = styled.button`
background: ${(props) =>
props.primary === true ? 'palevioletred' : 'white'};
color: ${(props) => (props.primary ? 'white' : 'palevioletred')};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;

render(
<div>
<Button>Normal</Button>
<Button primary={true}>Primary</Button>
</div>
);

Documentation

styled-components

Component Libraries

A UI component library is a set of ready-made UI components such as buttons, inputs, dialogs, and so on. They serve as building blocks for layouts. Thanks to their modular nature, we can arrange components in many different ways to achieve unique effects. Each library has a distinctive look and feel, but most of them offer theming, and their components are customizable to a certain degree.

Popular component libraries for React include React-Bootstrap, Theme UI, and Chakra UI. We'll be focusing on Chakra UI.

Libraries are made for one reason – to make developers’ lives easier. UI component libraries are no different in their purpose.

Benefits

  • Speed – incorporating a UI component library can have a great impact on development speed. Instead of creating each element from scratch, we simply mix and match the existing components. Even if some additional customization is required, it tends to be much quicker than writing styles on our own.
  • Ease of use – components are meant to be easy to use. Established libraries are well-organized and have good documentation that is easy to follow. Very often, it’s enough just to copy and paste code snippets to make it work.
  • Attractive look – components look great without requiring any extra effort from the developer; they’re carefully designed by professionals.
  • Compatibility – ensuring cross-browser and cross-device compatibility is one of the biggest challenges of frontend development. UI component libraries provide compatibility out of the box, which makes everything so simple!
  • Accessibility – good libraries adhere to accessibility guidelines, so developers don’t even need to think about it.

Drawbacks

  • Generic look – your app’s look and feel will be determined by the library’s style in most parts. This is not necessarily an issue, but you need to make sure that this is acceptable for your project.
  • Change of design direction – It’s very important that designers understand and stick to components offered by the library. If the direction changes towards a custom solution, it will become increasingly difficult and time-consuming to overwrite the initial implementation.
  • New team members – every developer and designer needs to be familiar with the particular library and its implementation (though this point is true for any design system and any project).
  • Bundle size – UI component libraries tend to be big, so it’s probably not the best idea to engage them in tiny projects.

Chakra-UI

Chakra UI is component library based on a few principles:

  • Style Props: All component styles can be overridden or extended via style props to reduce the use of css prop or styled(). Compose new components from Box.

  • Simplicity: Strive to keep the component API fairly simple and show real world scenarios of using the component.

  • Composition: Break down components into smaller parts with minimal props to keep complexity low, and compose them together. This will ensure that the styles and functionality are flexible and extensible.

  • Accessibility: When creating a component, keep accessibility top of mind. This includes keyboard navigation, focus management, color contrast, voice over, and the correct aria-* attributes.

  • Dark Mode: Make components dark mode compatible. Use useColorMode hook to handle styling. Learn more about dark mode.

  • Naming Props: We all know naming is the hardest thing in this industry. Generally, ensure a prop name is indicative of what it does. Boolean props should be named using auxiliary verbs such as does, has, is and should. For example, Button uses isDisabled, isLoading, etc.

For more info on Chakra versus other component libraries, check out their docs.

Installation

yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^5

Setup Provider

import * as React from 'react';

// 1. import `ChakraProvider` component
import { ChakraProvider } from '@chakra-ui/react';

function App({ Component }) {
// 2. Use at the root of your app
return (
<ChakraProvider>
<Component />
</ChakraProvider>
);
}

Incorporating

// Sample card from Airbnb

function AirbnbExample() {
const property = {
imageUrl: 'https://bit.ly/2Z4KKcF',
imageAlt: 'Rear view of modern home with pool',
beds: 3,
baths: 2,
title: 'Modern home in city center in the heart of historic Los Angeles',
formattedPrice: '$1,900.00',
reviewCount: 34,
rating: 4,
};

return (
<Box
maxW="sm"
borderWidth="2px"
borderRadius="lg"
overflow="hidden"
borderStyle="solid"
>
<Image src={property.imageUrl} alt={property.imageAlt} />
<Box p="6">
<Box display="flex" alignItems="baseline">
<Badge borderRadius="full" px="2" colorScheme="teal">
New
</Badge>
<Box
color="gray.500"
fontWeight="semibold"
letterSpacing="wide"
fontSize="xs"
textTransform="uppercase"
ml="2"
>
{property.beds} beds &bull; {property.baths} baths
</Box>
</Box>

<Box
mt="1"
fontWeight="semibold"
as="h4"
lineHeight="tight"
isTruncated
>
{property.title}
</Box>

<Box>
{property.formattedPrice}
<Box as="span" color="gray.600" fontSize="sm">
/ wk
</Box>
</Box>

<Box display="flex" mt="2" alignItems="center">
{Array(5)
.fill('')
.map((_, i) => (
<StarIcon
key={i}
color={i < property.rating ? 'teal.500' : 'gray.300'}
/>
))}
<Box as="span" ml="2" color="gray.600" fontSize="sm">
{property.reviewCount} reviews
</Box>
</Box>
</Box>
</Box>
);
}

React-Bootstrap

React-Bootstrap is a complete re-implementation of the Bootstrap components using React. It has no dependency on either bootstrap.js or jQuery. If you have React setup and React-Bootstrap installed, you have everything you need.

Methods and events using jQuery are done imperatively by directly manipulating the DOM. In contrast, React uses updates to the state to update the virtual DOM. In this way, React-Bootstrap provides a more reliable solution by incorporating Bootstrap functionality into React's virtual DOM.

Installation

yarn add react-bootstrap bootstrap

Incorporating Bootstrap

import React, { Component } from 'react';
import Alert from 'react-bootstrap/Alert';

const Example = () => {
return (
<Alert dismissible variant="danger">
<Alert.Heading>Oh snap! You got an error!</Alert.Heading>
<p>Change this and that and try again.</p>
</Alert>
);
};

export default Example;

Don't worry if you don't get what's going on here — you don't need to remember Bootstrap (and by extension ReactBootstrap!) Whatever you don't understand in the above block of text, google it!

Documentation

React-Bootstrap


Other Libraries (Optional)

There are many component libraries I haven't covered, and oftentimes larger projects and companies may create their own to fit their needs. I've included some other popular component libraries below. No component library is necessarily better than another, and each has pros and cons.

Material-UI: A popular React UI framework

Google's component library. The main complaint to using Material UI is that it's hard to customize and can thus leave some sites using a large amount of Material UI looking too much like something from Google.

Ant Design - The world's second most popular React UI framework

A library developed by the Chinese tech giant Alibaba.

Semantic UI

Lightweight CSS frameworks such as Tailwind or Pure can also be considered as viable alternatives to a component library. They offer a minimal, less opinionated CSS foundation that will help you speed up development, while at the same time allowing tremendous flexibility.

The Anatomy of a React App

React Project File Structure

A React app is composed of many different files and filetypes - what do each of them do and why do we need them? Knowing the answer to this question isn't knowledge that applies just to frontend engineering, but crucial to becoming a full-fledged software engineer.

README.md

Essentially a back-of-the-book summary of your code. Your README.md should describe what your code is for, what it does, and if applicable, it should provide a detailed overview of each file and its functions. Think about your README.md as a guide to your code.

package.json and package-lock.json

package.json is essentially a list of the dependencies of your app!

package-lock.json is a version-locked version of package.json, so that each new device that downloads the code downloads the correct dependencies. This is to prevent new updates to dependencies breaking your code.

node_modules

Where all your dependencies live! You should never ship out node_modules because its YUGE (try opening it up and you'll see). Always include node_modules in your .gitignore.

build

A minified build version of your app - All your code is transformed into an extremely compact version of itself, and this version is what is meant to be served to the public, since you get a huge speedup from using the build version! Run npm run build in the root directory of your app in the terminal to create the build folder!

Architecture and Design Methodologies

Read These First

Thinking in React - React

Design Principles - React

Extra Reading

React Architecture Best Practices and Tips from Community Experts

Atomic Design Methodology | Atomic Design by Brad Frost

Server-Side Rendering

note

Server-Side Rendering (SSR) is a more advanced tool in the react ecosystem so while we've decided not to teach it in-depth, it's still useful to know what it is and what its use case might be.

Performance is a central concern for frontend developers. We should always be striving to serve the leanest web apps that perform faster than humans can think. This is as much a game of psychology as it is a technological challenge. It's a challenge of loading the correct content first so a user can see a site and begin to make a decision of what they want to do (scroll down, click a button, log in, etc.) and then be prepared for that action before they make that decision.

Enter server-side rendering. This is a technique where you run React on your Node.js server before you serve the request to the user and send down the first rendering of your website already done. This saves precious milliseconds+ on your site because otherwise, the user has to download the HTML, then download the JavaScript, then execute the JS to get the app. In this case, they'll just download the HTML and see the first rendered page while React is loading in the background.

While the total time to when the page is actually interactive is comparable, if a bit slower, the time to when the user sees something for the first time should be much faster, hence why this is a popular technique.

A popular framework built on top of React that comes with server-side rendering is Next.js.

Next.js by Vercel - The React Framework

TLDR: Server Side Rendering makes websites go faster (usually).

Redux

note

Redux is a more advanced tool in the react ecosystem so while we've decided not to teach it in-depth, it's still useful to know what it is and what its use case might be.

Redux is a well-known library that does state management for you, similar to context in react. With context, you use the provider and consumer as a sort of portal to skip passing parameters through every component. With Redux, we're taking the state management out of React entirely and moving it to a separate store.

Why do we have Redux?

  1. Context used to be a lot worse to use and less useful. This made Redux (or Redux-like) management tools the only option
  2. Redux code is extremely testable. This is probably the most compelling reason to use it. Having your state mutation be broken up in such a way to make it easy to test is fantastic. This is also mitigated because we have useReducer now.
  3. The debugging story is pretty good.

How often will we use Redux? Never, I anticipate. I rarely had problems that Redux solved (they exist; I just didn't have them) and in the few cases now where I would see myself using Redux I think React's context hook would cover it. But if Redux speaks to you, do it! Don't let me stop you. It's a great library. Just be cautious. And there are reasons to use it: if you have complex orchestrations of async data, Redux can be immensely useful and I would use it for that.

Redux - A predictable state container for JavaScript apps. | Redux

TLDR: Redux is used to manage global state in React, but is being phased out by React's Context hook.

TypeScript

note

Typescript is a more advanced tool in the react ecosystem so while we've decided not to teach it in-depth, it's still useful to know what it is and what its use case might be.

Typescript is a static type object-oriented programming language maintained by Microsoft. It can be seen as a superset of JavaScript. With the help of Typescript Compiler (TSC), we can convert typescript code to JavaScript, and then it would be made understandable to the browser and to Node.

So, why do we use Typescript if we can directly write in JavaScript? There are scenarios where JavaScript may not function that well.

  • Since Typescript is a statically typed language, meaning that all the types can be checked during compile time, it can limit the number of mistakes during the run time. Thus easier to debug.
  • Static typing also provides highly productive development tools for JavaScript IDEs and practices, like static type checking.

As a result, Typescript is rapidly gaining in popularity nowadays.

note

We used to teach a lesson on TypeScript. You can find the old reading for it here.

Full-Stack DeCal Typescript Lesson:

Typescript

TLDR: Typescript = type-checked Javascript.

Conclusion

After this lesson, you hopefully have all the tools you'd need to build robust, large-scale web applications, and if not then you know where to look to learn about the information you'd need to do so. Frontend development is a vast landscape and is always changing, so make sure to keep that in mind while developing. We've introduced you to the core tools and ideas you'll need, but these tools and methodologies are constantly being updated. Software engineering is a constant learning cycle, so never be afraid to look into a new solution or an alternative method of implementing your ideas!


Contributors