Published Oct 29, 2023 ⦁ 9 min read

Build a web app with React, an open source framework

Introduction

React has quickly become one of the most popular open source frameworks for building user interfaces and web applications. Maintained by Facebook and backed by a thriving community of developers, React makes it easy to manage state and build complex, interactive UIs from simple, reusable components.

Some key benefits of React include:

  • Component architecture - React structures UI code into self-contained, modular components that can be composed together. This promotes separation of concerns and reusability. For example, a Button component can be reused across the app.
  • Virtual DOM - React uses a virtual representation of the real DOM and intelligently updates it when state changes, avoiding costly DOM manipulations. This improves performance significantly for complex UIs.
  • Managing state - React's unidirectional data flow and use of state hook make managing UI state simple and declarative. Local component state is easy to reason about.

In this tutorial, we'll build a simple web app to demonstrate core React concepts like components, props, state, and hooks for complete beginners. We'll assume you have basic knowledge of HTML, CSS, and JavaScript but may be new to React.

By the end, you'll have a solid foundation for building production-ready React apps and be ready to tackle more advanced features like routing, data fetching, and tooling. Let's get started!

Setting Up a React Project

Before we can start building with React, we need to set up a development environment and build process for our app. The fastest way to get started is using Create React App.

Create React App handles all the complex configuration needed for React projects - Webpack, Babel, ESLint, etc. To set it up:

npx create-react-app my-app
cd my-app
npm start

This scaffolds a project with an optimized production-ready build, dev server, and other tools needed to kickstart development.

Alternative setup options include Next.js, Gatsby, or configuring Webpack manually. But Create React App works well for learning and simple projects.

We'll also initialize a Git repository to enable version control for our app:

git init

And create a .gitignore file to exclude files like node_modules.

Project Structure Overview

The Create React App folder structure includes:

  • src - Contains our React code
  • public - Static assets like index.html
  • package.json - Defines dependencies and scripts
  • node_modules - Downloaded dependencies

src/index.js renders the root App component into the DOM. src/App.js will be the root component for our app.

Component diagram

Component relationship diagram

Dependencies Overview

Key dependencies created include:

  • React - Main React library
  • ReactDOM - Used to render components to DOM
  • Babel - Transpiles modern JavaScript
  • Webpack - Bundles app and assets for production

These are all preconfigured and hidden away in Create React App. Additional libraries can be added later as needed.

Building React Components

React apps are built using components - reusable, modular pieces of UI code.

Components can be defined as functions or classes:

// Function component
function Header() {
  return <h1>My Website</h1>;
}

// Class component 
class Header extends React.Component {
  render() {  
    return <h1>My Website</h1>;
  }
}

All components must have a render() method returning JSX markup to render.

JSX Syntax

JSX allows writing HTML-like syntax in React:

const element = <h1 className="header">Hello World</h1>; 

It compiles to regular JavaScript but provides a templating mechanism for React components.

Note differences like using className instead of class for adding CSS classes.

Component Composition

Components can render other components, allowing complex UIs to be built from simple building blocks:

function App() {

  return (
    <div>
      <Header />
      <Content />
    </div>
  );

}

function Header() {
  return <h1>My Website</h1>;
}

function Content() {
  return <p>This is the content</p>; 
}

Data gets passed between components using props:

<Header title="My Website"/>

Props can be destructured right in the function parameters:

function Header({ title }) {
  return <h1>{title}</h1>; 
}

This composition is a key advantage of React.

Managing State with Hooks

State allows components to manage data that determine rendering.

React provides special functions called hooks for state and other features. The useState hook initializes state:

import { useState } from 'react';

function App() {

  const [count, setCount] = useState(0); // Initialize with 0
  
  return (
    // Omitted
  );

}

useState returns the current state value and a function to update it. We can call setCount to change the count state variable.

Other useful builtin hooks include useEffect, useRef, useContext, etc.

Handling Events

We can handle user events like clicks by attaching event handlers:

function App() {

  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(prevCount => prevCount + 1); // Update state
  }
  
  return (
    <button onClick={handleClick}> // Attach handler
      Click
    </button>
  );

}

Event handlers can also be passed between components via props:

<Button onClick={handleClick} /> 

This allows component reuse and separation of concerns.

Updating the UI

When state is updated with setCount, React re-renders the component with the new state value.

This happens in two phases:

  • Render - Components rerender with updated state
  • Commit - Changes are applied to DOM

So updating count will show the new value:

<p>You clicked {count} times</p>

React handles updating the DOM efficiently using its virtual representation.

Styling and CSS

There are several ways to style React apps:

  • Import CSS files - import './styles.css'
  • CSS Modules - For scoped component styles
  • Inline styles - With JavaScript object literals
  • CSS-in-JS - Libraries like Styled Components

A best practice is to keep component code separate from styles.

Global Styles

Global styles affect the entire app. They can be defined in src/index.css and imported in src/index.js:

/* index.css */

body {
  margin: 0;
  font-family: sans-serif; 
}
/* Index.js */

import './index.css'; // Imports global styles

Global styles are loaded at the root before components.

Scoped Styles

For component-specific styles, CSS Modules or styled-components can scope CSS to each component.

This avoids global side effects but requires more setup:

// App.module.css

.title {
  /* Scoped to App */ 
}

// App.js

import styles from './App.module.css';

function App() {
  return <h1 className={styles.title}>Hello World</h1>; 
}

Overall, keeping components self-contained with scoped CSS is preferred for modularity.

Data Fetching

Components often need to fetch data from an API endpoint.

The useEffect hook runs code after render, allowing data fetching:

useEffect(() => {

  fetch('https://jsonplaceholder.typicode.com/posts')  
    .then(res => res.json())
    .then(data => {
      setPosts(data);
    })

}, []); // Empty array = run once on mount

Here we fetch posts from a sample API and save them to state on mount.

useEffect unifies lifecycle methods like componentDidMount into one API.

It runs after render allowing interaction with rendered DOM elements.

useEffect

useEffect accepts a callback function that runs after render:

useEffect(() => {
  // Run after render
});

The second argument controls when it runs:

  • [] - Only on mount
  • No array - On every render
  • [count] - When count changes

This allows flexible synchronization of effects.

Component Lifecycle

Class components had separate lifecycle methods like componentDidMount.

useEffect unifies these into a single API:

  • componentDidMount - useEffect(() => {}, [])
  • componentDidUpdate - useEffect(() => {})
  • componentWillUnmount - Return cleanup function

So we can fetch data on mount with:

useEffect(() => {
  // Fetch data 
}, []); 

Routing and Navigation

For multi-page apps, React Router manages routing:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/about" element={<About />} /> 
  </Routes>
</BrowserRouter>

Routes are declared and matched based on path. Nested routes, parameters, and more are supported.

Linking Between Pages

The <Link> component renders a link for declarative navigation between pages:

<Link to="/about">About</Link> 

Styling the active link is easy:

<Link to="/about" className={({ isActive }) => (isActive ? 'active' : '')}>

This avoids imperatively pushing routes.

Lazy Loading

To load bundles on demand, components can be lazily loaded with React.lazy and Suspense:

const Home = React.lazy(() => import('./Home'));

function App() {
  return (
    <Suspense fallback={<Loader />}>
      <Home /> 
    </Suspense>
  );  
}

This helps improve initial load time. Caveats include shared dependencies.

Deployment and Hosting

To share a React app, we need to deploy it. Let's look at build process and hosting options.

The project can be built for production using:

npm run build

This optimizes the output in build/ for deployment.

Build Process

npm run build:

  • Minifies and transpiles ES6+ to ES5
  • Inlines CSS, optimizes images
  • Replaces development variables
  • Generates production-ready build

All configuration is handled by Create React App's Webpack setup.

Deployment Options

There are many hosting options for React apps:

  • Static site hosting - Vercel, Netlify, GitHub Pages
  • Traditional servers - Node.js, Nginx
  • Serverless - AWS Lambda, Azure Functions

Free services like Vercel and Netlify simplify deployment with continuous integration and deployment.

For server-side rendering, a Node.js server is required.

Conclusion and Next Steps

We covered a lot of ground introducing React concepts like components, props, state, JSX, hooks, routing, and deployment options.

React's component model and virtual DOM make it ideal for building complex, reactive user interfaces. There is a thriving ecosystem of libraries like React Router and Styled Components that enhance its capabilities.

Some areas for further learning include advanced state management with Redux or MobX, unit testing, form handling, performance optimization, and integrating React with backend frameworks like Node.js and Django.

React Native also allows building mobile apps with React. Overall, React is an excellent open source framework for crafting modern web applications.

To recap, we:

  • Set up a React dev environment
  • Built components and used JSX
  • Managed state with hooks like useState
  • Added styles, fetched data, handled routing
  • Looked at build process and deployment options

You should now have the foundation to start building your own React apps! The DevHunt community is also a great place to find and promote new open source libraries and frameworks like React to enhance your development workflow.