Freemote Logo
Background pattern

Don't Forget
React
Cheat Sheet

React Logo

Getting Started

Everything you need to start building with React

React Fundamentals

Core concepts you need to understand React

Advanced Concepts

Take your React skills to the next level

React Ecosystem

Popular tools and frameworks in the React ecosystem

Getting Started

Everything you need to start building with React

When to Use React?

React isn't always the best choice. Here's a comparison with alternatives:

REACT USE CASES

React shines in these scenarios:
  • Websites that need to update content without refreshing the page
  • Apps with lots of reusable pieces (like buttons, cards, forms)
  • When you want to use pre-made components from other developers (libraries)
  • When your team knows JavaScript well
  • When you want to build a professional web app

VS VANILLA JAVASCRIPT

Vanilla JavaScript

Simple websites, landing pages, or when you're learning web development basics

Pros:
  • Works directly in the browser
  • Can use without external libraries
  • Can be faster
Cons:
  • Harder to re-use code
  • Harder to keep code organized
  • More manual work

VS VUE.JS

Vue.js

Smaller projects, or when you want an easier learning curve

Pros:
  • Easier to learn than React
  • Good documentation
  • HTML-like syntax
Cons:
  • Fewer job opportunities
  • Fewer ready-made components
  • Less popular in big companies

VS SVELTE

Svelte

Small to medium projects, or when website speed is very important

Pros:
  • Less code to write
  • Faster websites
  • Simple to understand
Cons:
  • Newer and less popular
  • Harder to find help
  • Fewer tutorials

Setting Up React

Everything you need to start your first React project

WHAT YOU'LL NEED

Code Editor

VS Code is recommended for React development

  1. Download VS Code from code.visualstudio.com

Node.js & npm

Node.js includes npm (Node Package Manager)

  1. Download Node.js from nodejs.org
  2. This automatically installs npm
  3. Verify with 'node --version' and 'npm --version' in terminal

QUICK START

# Create new Next.js project (recommended)
npx create-next-app@latest my-app

# Navigate to project
cd my-app

# Install dependencies
npm install

# Start development server
npm run dev
Choose one of these commands to create your first React project. Follow the prompts in your terminal. Once installed, open the project folder in VS Code.

ADDING LIBRARIES

# Install a single library
npm install react-icons

# Install multiple libraries
npm install axios react-query @mui/material

Use npm install to add additional libraries to your project. This is just code other people have written and it saves you a lot of time.

UNDERSTANDING THE STRUCTURE

my-react-app/
  ├── node_modules/   # Dependencies
  ├── public/        # Static files
  ├── src/           # Your code goes here
  │   ├── app/       # Your pages (in Next.js)
  │   └── components/# Reusable components
  ├── package.json   # Project configuration
  └── README.md      # Documentation
Don't worry too much about the structure at first. Focus on the src folder - that's where you'll write your code.

React Fundamentals

Core concepts you need to understand React

JSX

Almost like HTML, with a few key differences

SELF-CLOSING TAGS

// In HTML:
<input type="text" >
<img src="person.png" alt="person" >

// In React:
<input type="text" />
<img src="person.png" alt="person" />
All tags must now have a (self) closing tag (for example, input and img)

CLASS BECOMES CLASSNAME

// In HTML:
<p class="primary-text"></p>

// In React:
<p className="primary-text"></p>
The class attribute becomes className in React

STYLE SYNTAX

// In HTML:
<p style="color: white"></p>

// In React:
<p style={{ color: "white" }}></p>
Style attribute now takes a JavaScript object instead of a string

COMPONENTS

function MyComponent() {
  return <p>This is JSX!</p>
}
Using JSX, we can create "custom" elements, with their own structure, properties, logic, and styling. In React these are known as components. Components must return JSX.

EVENT HANDLERS

function MyComponent() {
  return (
    <form onSubmit={...}>
      <input type="text" onChange={...} />
      <button onClick={...}>Click me!</button>
      <input type="submit" />
    </form>
  )
}
camelCase "Handler" properties onClick, onChange, and onSubmit replace addEventListener for user events in JSX.

EVENT HANDLER SYNTAX

// ❌ This doesn't work right
<button
  onClick={console.log("clicked")}
>
  Click me!
</button>

// ✅ This does (note anonymous function)
<button
  onClick={() => console.log("clicked")}
>
  Click me!
</button>
They take a function as a value. Don't Call this Function! Use an anonymous / wrapper function if necessary.

EVENT OBJECT USAGE

<input
  type="text"
  onChange={e => console.log
  (e.target.value)} />
returns logs everytime we type
The "event object" (e) will contain the data you need for "onChange" in a text input, ex:

EVENT OBJECT OPTIONAL

<button
  onClick={() => setClicked(true)}
>
  Click me
</button>
returns sets state variable on click
You don't always NEED the event object, though, and can instead define a function without parameters.

Components

Think of Components as "Custom JSX Elements" that we can define, and then use one or more times. Ultimately, the components are just like variables which will be converted to HTML.

COMPONENT DEFINITION

// MyComponent.js
export default function MyComponent() {
  return <p>This is JSX!</p>
}
A component is just a function that returns JSX

COMPONENT USAGE

// App.js
import MyComponent from "./MyComponent";
export default function App() {
  return (
    <>
      <MyComponent />
      <MyComponent />
      <MyComponent />
    </>
  );
}
Once defined, Components can be reused multiple times

HTML OUTPUT

<!-- index.html -->
<p>This is JSX!</p>
<p>This is JSX!</p>
<p>This is JSX!</p>
React converts your components into regular HTML

COMPONENT SIZE

How big should components be? There's no hard limit, but a couple rules of thumb:
  • Will this component be used more than once?
  • Does it make sense as a logical grouping? Ex. a navigation bar, or page layout
  • Does it handle logic, or just display data?

The Component Tree

The convention is 1 component per file. We MUST export components to use them in other files

EXPORT COMPONENT

export default function MyComponent() { ... }
Export the component so it can be used in other files

IMPORT COMPONENT

import MyComponent from "./MyComponent";
(the extension .js or .jsx is optional when importing)

COMPONENT COMPOSITION

export default function AllMyComponents() {
  return (
    <>
      <MyComponent />
      <MyComponent />
      <MyComponent />
    </>
  )
}
As above, our components will go inside one another, and we can use them multiple times.

Props

The "arguments" of a component, they're how we pass data from one component to another.

PASSING PROPS

<MyComponent name="Aaron" />
Think of them as "custom properties" – we send them with the "key=value" syntax

RECEIVING PROPS

function MyComponent(props) {
  console.log(props.name);
  // Aaron prints
}
And receive them with 'props' object – so they can be accessed accordingly.

DESTRUCTURING PROPS

function MyComponent({ name }) {
  return <p>Hello, {name}</p>
}
We can "destructure" them like so...

PROPS IN PRACTICE

// React
function AllMyComponents() {
  return (
    <div>
      <MyComponent name="Aaron" />
      <MyComponent name="Jack" />
      <MyComponent name="Jan" />
    </div>
  )
}

// HTML Result
<div>
  <p>Hello, Aaron</p>
  <p>Hello, Jack</p>
  <p>Hello, Jan</p>
</div>
In the tree model, passing props might look like this, which turns into this html

SAVING TIME WITH .MAP

const names = ["Aaron", "Jack", "Jan"];

function AllMyComponents() {
  return (
    <div>
      {names.map(name => (
        <MyComponent key={name} name={name} />
      ))}
    </div>
  )
}

// Same HTML Result
<div>
  <p>Hello, Aaron</p>
  <p>Hello, Jack</p>
  <p>Hello, Jan</p>
</div>
When re-using the same components, we can also use .map(). The result will be the same as above. Using map, React will ask you to add a 'key' prop, which can be the index or a unique value. It has no effect on the DOM, but is used by React to optimize rendering.

State & State Hook

The "internal variables" of a component.

DECLARING STATE

import React from 'react'
function MyComponent() {
  const [myName, setMyName] = 
    React.useState("Aaron")
  ...
}
State must go INSIDE our component, conventionally, at the top. We create them with useState hook, that takes an "initial value" returns an array of 2

UPDATING STATE

setMyName("Jack");  // correct

myName = "jack";    // won't work
And we can update "myName" using the setter function. But cannot assign anything directly to state (always use the setter function!)

STATE WITH ARRAYS

const [myNames, setMyNames] = 
  React.useState(["Aaron"]);

// won't work
myNames.push("Jack")

// works, creates a copy with array
// spreading, adds "Jack" at the end
setMyNames([...myNames, "Jack"]);
State is IMMUTABLE. It means we can't modify directly after creation. If we want to update an array, we need to create a new copy

Styling With React

In React, you can still use CSS files, for sure. But Styled Components are more popular, especially with UI component libraries (see next section).

BASIC STYLED COMPONENT

const Block = styled.div`
  margin: 10px;
  padding: 10px;
`;
For example, I can create a "Block" component that is simply a "div" under the hood, that includes some padding and margin.

EXTENDING STYLES

const SmallBlock = styled(Block)`
  width: 100px;
`

const BigBlock = styled(Block)`
  width: 200px;
`
And I can "extend" this block with more styles to create "BigBlock" and "SmallBlock" styled components.

STYLED COMPONENTS USAGE

// Using the components
<SmallBlock>Small content</SmallBlock>
<BigBlock>Larger content</BigBlock>
You'll either use the "styled-components" library or the "styled" function of a UI Library like Material UI to do this.

Advanced Concepts

Take your React skills to the next level

useEffect & React Life Cycle

When components get added to the page, they start the "component life cycle" There are 3 key events: Mount, Update, UnMount

LIFECYCLE

MOUNT

Component is added to DOM. useEffect with empty [] runs here.

UPDATE

Props or state change. useEffect with dependencies runs here.

UNMOUNT

Component is removed. useEffect cleanup functions run here.

BASIC USEEFFECT

import React from 'react'
function MyComponent() {
  React.useEffect(() => {
    fetch("https://myserverurl.com/items")
      .then(...)
  }, [])
}
We often useEffect to fetch some data once and only once, so we aren't unnecessarily bombarding our server. It takes a function as the first argument (this cannot be an async function)...

DEPENDENCIES ARRAY

React.useEffect(() => {
  fetch("https://myserverurl.com/items/" + itemID)
    .then(...)
}, [itemID])
Optionally, an array of "dependencies" as the second argument - These are the variables we can choose to "watch" then if they change, we run the function again

CLEANUP FUNCTION

React.useEffect(() => {
  return () => alert("goodbye!")
}, [])
Optionally, we can also return a function which runs on "unmount". Only runs when component gets removed from DOM

React Router

React Router enables us to do "Client Side Routing", so we can have some navigation in our React apps with multiple pages and paths that can be observed in the URL bar.

HTML VS REACT ROUTING

// index.html
<h1>Hello there!</h1>
<a href="faq.html">Go to FAQ</a>

// faq.html
<h1>FAQ</h1>
<a href="index.html">Go to home</a>
While in HTML, we'd need a different file and server request for each path...

REACT ROUTER SETUP

import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
import Home from "./Home"
import Faq from "./Faq"

function App() {
  return(
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="expenses" element={<Faq />} />
      </Routes>
    </BrowserRouter>
  );
}
We can achieve the same result with React components by1. wrapping our App in a "BrowserRouter"2. creating <Routes> with the "path" and "element" parameters (setting each path to a component)

Context & Provider

Share state between components without prop drilling. Context provides a way to pass data through the component tree without having to pass props manually at every level.

CREATING CONTEXT

// ThemeContext.js
import { createContext } from 'react';

export const ThemeContext = createContext();

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}
Create a context file with a Provider component that will wrap parts of your app that need access to this context

USING CONTEXT

// App.js
import { ThemeProvider } from './ThemeContext';

function App() {
  return (
    <ThemeProvider>
      <Header />
      <MainContent />
      <Footer />
    </ThemeProvider>
  );
}
Wrap components that need access to the context with the Provider

CONSUMING CONTEXT

// DeepNestedComponent.js
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';

function DeepNestedComponent() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <button onClick={() => setTheme(
      theme === 'light' ? 'dark' : 'light'
    )}>
      Current theme: {theme}
    </button>
  );
}
Any nested component can access the context values using the useContext hook

CONTEXT VS PROPS

When should you use Context vs Props?
  • Use Context for global state (theme, user auth, language)
  • Use Props for component-specific data
  • Context can make components less reusable
  • Don't overuse - Context changes trigger re-renders

Debugging React

Common debugging techniques and tools to find and fix problems in your React apps

REACT DEVELOPER TOOLS

Install the React Developer Tools browser extension to:
  • Inspect component props and state
  • See component hierarchy
  • Track component re-renders
  • Debug performance issues
  • View source locations

COMMON ERROR MESSAGES

// Objects are not valid as React child
return <div>{myObject}</div>  // ❌
return <div>{JSON.stringify(myObject)}</div>  // ✅

// Cannot update a component while rendering
function Bad() {
  const [count, setCount] = useState(0)
  setCount(count + 1)  // ❌ Infinite loop!
}

// Missing dependencies in useEffect
useEffect(() => {
  console.log(data)  // ESLint warning
}, [])  // Missing 'data' dependency
Learn to recognize and fix common React errors

CONSOLE DEBUGGING

function MyComponent({ data }) {
  console.log('Component rendered:', { data })
  
  useEffect(() => {
    console.log('Effect ran:', { data })
    return () => console.log('Cleanup:', { data })
  }, [data])

  return <div>{/* ... */}</div>
}
Strategic console.log placement helps understand component lifecycle and data flow

Deploying React Apps

Learn how to put your React app on the internet

BUILD YOUR APP

# Create production build
npm run build

# Preview build locally
npm run preview
Before deploying, create an optimized production build of your app

ON VERCEL

Vercel Logo

Key Features

  • Best option for Next.js projects
  • Automatic deployments from Git
  • Built-in analytics and monitoring
  • Great developer experience

ON NETLIFY

Netlify Logo

Key Features

  • Great for static React apps
  • Simple Git integration
  • Includes CDN and SSL
  • Form handling built-in
  • Free tier available

ON GITHUB PAGES

GitHub Logo

Key Features

  • Free hosting for public repos
  • Direct integration with GitHub
  • Manual deployment process
  • Good for personal projects
  • Requires some configuration

TypeScript with React

TypeScript helps catch errors before they happen by adding types to your code

COMPONENT PROPS

// Define the shape of your props
type ButtonProps = {
  text: string
  onClick: () => void
  color?: 'primary' | 'secondary'
}

// Use them in your component
function Button({ 
  text, 
  onClick, 
  color = 'primary' 
}: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={color}
    >
      {text}
    </button>
  )
}
Define the types of props your component accepts. The ? means optional

TYPING HOOKS

// State with type
const [user, setUser] = useState<User | null>(null)

// Event with type
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setUser(e.target.value)
}
Add types to your hooks and event handlers

Common React Patterns

Frequently used patterns and solutions in React applications

LAYOUT PATTERN

// Layout.js
export default function Layout({ children }) {
  return (
    <div>
      <nav>{/* Navigation */}</nav>
      <main>{children}</main>
      <footer>{/* Footer */}</footer>
    </div>
  )
}

// Page.js
export default function Page() {
  return (
    <Layout>
      <h1>My Page Content</h1>
    </Layout>
  )
}
Wrap pages with a layout component to share common elements like navigation and footer

AUTH PATTERN

function PrivateRoute({ children }) {
  const { user } = useAuth()
  
  if (!user) {
    return <Navigate to="/login" />
  }
  
  return children
}

// Usage
<PrivateRoute>
  <SecretPage />
</PrivateRoute>
Protect routes that require authentication

LOADING STATES

function ProductList() {
  const [isLoading, setIsLoading] = 
    useState(true)
  const [error, setError] = useState(null)
  const [data, setData] = useState([])

  if (isLoading) return <Spinner />
  if (error) return <Error message={error} />
  
  return <div>{/* Show data */}</div>
}
Always handle loading and error states in components that fetch data

Common React Mistakes

Learn from others' mistakes - avoid these common pitfalls when building React apps

STATE MISTAKES

// ❌ Modifying state directly
const [user, setUser] = useState({ name: 'John' })
user.name = 'Jane'  // Wrong!

// ✅ Using setState correctly
setUser({ ...user, name: 'Jane' })  // Correct!

// ❌ Using state value right after setting it
setCount(count + 1)
console.log(count)  // Still shows old value!

// ✅ Use useEffect to react to changes
useEffect(() => {
  console.log(count)  // Shows new value
}, [count])
State updates are not instant! They're scheduled for the next render. Never modify state directly.

USEEFFECT MISTAKES

// ❌ Missing dependencies
useEffect(() => {
  setUser(data)
}, [])  // Warning: 'data' is missing!

// ✅ Including all dependencies
useEffect(() => {
  setUser(data)
}, [data])

// ❌ Infinite loop
useEffect(() => {
  setCount(count + 1)
})  // No dependency array = runs every render!

// ✅ Controlled updates
useEffect(() => {
  setCount(count + 1)
}, [someValue])
useEffect is tricky! Always include dependencies and watch out for infinite loops.

RENDER MISTAKES

// ❌ Creating components inside components
function ParentComponent() {
  // This creates a new ChildComponent every render!
  function ChildComponent() { return <div>Child</div> }
  return <ChildComponent />
}

// ✅ Define components outside
function ChildComponent() { return <div>Child</div> }
function ParentComponent() {
  return <ChildComponent />
}
Components should be defined outside other components to prevent unnecessary re-renders

PROPS MISTAKES

// ❌ Modifying props
function Child(props) {
  props.value = 123  // Never modify props!
}

// ✅ Use state if you need to modify values
function Child(props) {
  const [value, setValue] = useState(props.value)
}

// ❌ Not handling null/undefined props
function Profile({ user }) {
  return <h1>{user.name}</h1>  // Crashes if user is null!
}

// ✅ Always handle edge cases
function Profile({ user }) {
  if (!user) return <div>Loading...</div>
  return <h1>{user.name}</h1>
}
Props are read-only! Never modify them directly, and always handle edge cases

KEY MISTAKES

// ❌ Using index as key in dynamic lists
{items.map((item, index) => (
  <Item key={index} />  // Bad for lists that change!
))}

// ✅ Using unique, stable IDs
{items.map((item) => (
  <Item key={item.id} />
))}
Using index as key can cause issues with list updates. Use unique IDs when possible.

EVENT HANDLER MISTAKES

// ❌ Calling function instead of passing it
<button onClick={handleClick()}>  {/* Wrong! */}

// ✅ Passing the function reference
<button onClick={handleClick}>  {/* Correct! */}

// ❌ Not preventing form submit default
<form onSubmit={handleSubmit}>

// ✅ Preventing default behavior
<form onSubmit={(e) => {
  e.preventDefault()
  handleSubmit()
}}>
Common event handling mistakes that can cause unexpected behavior

CONDITIONAL RENDERING MISTAKES

// ❌ Using statements in JSX
return (
  <div>
    {if (condition) {  // Won't work!
      return <span>Hi</span>
    }}
  </div>
)

// ✅ Using expressions instead
return (
  <div>
    {condition && <span>Hi</span>}
    {condition ? <span>Hi</span> : <span>Bye</span>}
  </div>
)
JSX only accepts expressions, not statements. Use ternary operators or logical AND.

React Ecosystem

Popular tools and frameworks in the React ecosystem

React Frameworks

Modern React development often uses a framework. Here are the most popular options:

NEXT.JS

Next.js

Professional websites that need good performance and SEO

Pros:
  • Pre-built or dynamic pages
  • Easy Vercel deployment
  • Good for SEO
Cons:
  • Strict rules & structure
  • Moderate learning curve

REMIX

Remix

Web apps that need to work well even with slow internet

Pros:
  • Good error handling
  • Works without JavaScript
  • Fast page loads
Cons:
  • Very new
  • Fewer tutorials available
  • Different mental model

GATSBY

Gatsby

Blogs, marketing sites, and content-heavy websites

Pros:
  • Fast static websites
  • Great for blogs
  • Lots of plugins
Cons:
  • Slow to build
  • Needs GraphQL knowledge
  • Not great for dynamic content

VITE

Vite

When you want a simple, fast, minimal way to start a React project

Pros:
  • Very fast development
  • Easy to set up
  • Modern features
Cons:
  • Less features out of the box
  • More setup required