React Fundamentals
React is a JavaScript library for building user interfaces, particularly single-page applications. It’s used to handle the view layer for web and mobile apps and allows you to create reusable UI components.
Introduction to React
React was created by Facebook and released in 2013. It’s maintained by Facebook and a community of individual developers and companies. React’s key features include:
- Declarative: You describe what your UI should look like, and React efficiently updates and renders the right components when data changes.
- Component-Based: Build encapsulated components that manage their own state, then compose them to make complex UIs.
- Learn Once, Write Anywhere: React can also render on the server using Node, and power mobile apps using React Native.
Setting Up a React Application
Using Create React App
The easiest way to start with React is using Create React App:
1 | npx create-react-app my-app |
This creates a new React application with a development server, modern JavaScript features, and optimized production build.
Project Structure
A typical Create React App project has this structure:
1 | my-app/ |
Manual Setup
For more control, you can set up React manually with webpack or another build tool:
1 | mkdir my-react-app |
Then create webpack and Babel configuration files.
React Components
Components are the core building blocks of React applications. Each component is a JavaScript function or class that optionally accepts inputs (props) and returns a React element describing what should appear on the screen.
Functional Components
Functional components are the simplest way to define a component:
1 | function Welcome(props) { |
Class Components
Class components offer more features like local state and lifecycle methods:
1 | import React, { Component } from 'react'; |
Component Composition
Components can refer to other components in their output:
1 | function App() { |
Extracting Components
Break down components into smaller components for better reuse and separation of concerns:
1 | function Comment(props) { |
JSX
JSX is a syntax extension to JavaScript that looks similar to HTML but comes with the full power of JavaScript. It’s recommended to use it with React to describe what the UI should look like.
JSX Basics
1 | const element = <h1>Hello, world!</h1>; |
JSX Represents Objects
Babel compiles JSX down to React.createElement()
calls:
1 | // This JSX: |
JSX Attributes
1 | // String literals |
JSX Children
1 | // Empty elements |
JSX Prevents Injection Attacks
React DOM escapes any values embedded in JSX before rendering them, helping to prevent XSS attacks:
1 | const title = response.potentiallyMaliciousInput; |
Props
Props (short for “properties”) are inputs to React components. They allow you to pass data from a parent component to a child component.
Passing Props
1 | // Parent component passing props |
Props are Read-Only
A component must never modify its own props. All React components must act like pure functions with respect to their props:
1 | // Correct |
Default Props
You can define default values for props:
1 | function Button(props) { |
Type Checking with PropTypes
You can use PropTypes to document the intended types of properties:
1 | import PropTypes from 'prop-types'; |
State and Lifecycle
State allows React components to change their output over time in response to user actions, network responses, and anything else.
Adding State to a Class Component
1 | class Clock extends React.Component { |
Lifecycle Methods
Components have lifecycle methods that allow you to run code at particular times:
1 | class Clock extends React.Component { |
Updating State
Never modify state directly; use setState()
instead:
1 | // Wrong |
State updates may be asynchronous:
1 | // Wrong |
State updates are merged:
1 | this.state = { |
Data Flows Down
State is often called local or encapsulated, and is not accessible to any component other than the one that owns and sets it. A component may pass its state down as props to its child components:
1 | function FormattedDate(props) { |
Handling Events
React events are named using camelCase, and you pass a function as the event handler, rather than a string:
1 | // HTML |
Event Handlers
1 | class Toggle extends React.Component { |
Alternative Class Syntax with Public Class Fields
1 | class Toggle extends React.Component { |
Passing Arguments to Event Handlers
1 | <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> |
Conditional Rendering
In React, you can create distinct components that encapsulate the behavior you need, then render only some of them depending on the state of your application.
If Statements
1 | function UserGreeting(props) { |
Inline If with Logical && Operator
1 | function Mailbox(props) { |
Inline If-Else with Conditional Operator
1 | render() { |
Preventing Component from Rendering
1 | function WarningBanner(props) { |
Lists and Keys
Rendering Multiple Components
1 | function NumberList(props) { |
Keys
Keys help React identify which items have changed, added, or removed:
1 | const todoItems = todos.map((todo) => |
Keys should be unique among siblings, but don’t need to be globally unique:
1 | function Blog(props) { |
Extracting Components with Keys
Keys only make sense in the context of the surrounding array:
1 | function ListItem(props) { |
Forms
HTML form elements work a bit differently in React because they naturally keep some internal state.
Controlled Components
In React, mutable state is typically kept in the state property of components, and only updated with setState()
. Form elements that are controlled by React in this way are called “controlled components”:
1 | class NameForm extends React.Component { |
Handling Multiple Inputs
When you need to handle multiple controlled inputs, you can add a name
attribute to each element and let the handler function choose what to do based on the value of event.target.name
:
1 | class Reservation extends React.Component { |
Form Controls
React supports various HTML form elements:
- Text inputs:
<input type="text">
,<textarea>
- Checkboxes:
<input type="checkbox">
- Radio buttons:
<input type="radio">
- Select dropdowns:
<select>
,<option>
- File inputs:
<input type="file">
(uncontrolled)
Lifting State Up
Often, several components need to reflect the same changing data. It’s recommended to lift the shared state up to their closest common ancestor.
1 | function BoilingVerdict(props) { |
When we need to support both Celsius and Fahrenheit, we lift state to the shared parent component:
1 | class Calculator extends React.Component { |
Composition vs Inheritance
React has a powerful composition model, and recommends using composition instead of inheritance to reuse code between components.
Containment
Components that don’t know their children ahead of time can use the special children
prop to pass children elements directly into their output:
1 | function FancyBorder(props) { |
Specialization
Sometimes we think about components as being “special cases” of other components. In React, this is also achieved by composition, where a more “specific” component renders a more “generic” one and configures it with props:
1 | function Dialog(props) { |
Thinking in React
Here’s a thought process for building React apps:
- Start with a mock: Break the UI into a component hierarchy
- Build a static version: Build components that reuse other components and pass data using props. Don’t use state yet.
- Identify the minimal representation of UI state: Figure out what state your app needs.
- Identify where your state should live: Identify which component should own which state.
- Add inverse data flow: Support data flowing from forms back up to parent components.
React Developer Tools
React Developer Tools is a browser extension for Chrome and Firefox that allows you to inspect the React component hierarchy in the browser’s developer tools:
- Inspect component props and state
- Track which components re-render
- Profile performance
- Find components that cause unintended side effects
Best Practices
Keep Components Small and Focused
Each component should ideally do one thing well. If a component grows too large, consider breaking it down into smaller subcomponents.
Use Functional Components When Possible
Functional components are simpler, more concise, and generally easier to understand than class components.
Use PropTypes for Type Checking
Define PropTypes for your components to document the API and catch bugs early.
Use CSS-in-JS or CSS Modules
Consider using CSS-in-JS libraries like styled-components or CSS Modules to scope styles to specific components.
Use Fragment to Avoid Unnecessary DOM Nodes
Use React Fragments to group lists of children without adding extra nodes to the DOM:
1 | function ListItems() { |
Use Short-Circuit Evaluation for Conditional Rendering
1 | {isLoggedIn && <LogoutButton />} |
Use Ternary Operator for Simple Conditionals
1 | {isLoggedIn ? <UserGreeting /> : <GuestGreeting />} |
Use Error Boundaries to Catch Rendering Errors
1 | class ErrorBoundary extends React.Component { |
Learning Resources
- React Documentation - Official React docs
- React Tutorial - Official React tutorial
- React Blog - Official React blog
- Create React App - Set up a modern web app by running one command
- React DevTools - React Developer Tools extension
- React Patterns - Common React patterns
- Egghead.io React Courses - Video tutorials
- React Enlightenment - React book