REACT Tutorial Course

Introduction to React

What is React?

React is a popular JavaScript library for building user interfaces, particularly for single-page applications where you need a fast, interactive experience. Developed and maintained by Facebook, React allows developers to create large web applications that can update and render efficiently in response to data changes.

Key features of React
  • Component-Based Architecture: React encourages building reusable components, which can be combined to create complex user interfaces. Each component manages its own state and can be composed to form a larger application.

  • Virtual DOM: React uses a virtual DOM, a lightweight copy of the actual DOM. When the state of an object changes, React updates the virtual DOM first, then efficiently updates the real DOM, reducing the number of manipulations and improving performance.

  • Unidirectional Data Flow: React ensures that data flows in one direction, making it easier to understand how data is passed and handled within the application, especially in larger apps.

  • JSX: React uses JSX, a syntax extension that allows you to write HTML-like code within JavaScript. This makes it easier to visualize the structure of your UI directly within your code.

  • Ecosystem and Community: React has a strong community and a rich ecosystem of tools, libraries, and extensions, making it a preferred choice for many developers for building web applications.

History of React

React was initially developed by Jordan Walke, a software engineer at Facebook. It was first deployed on Facebook's news feed in 2011 and later on Instagram in 2012.

  • Initial Development: Jordan Walke, a Facebook engineer, created the initial prototype of React, which was called "FaxJS" at the time. It was inspired by XHP, an HTML component library for PHP that Facebook used.

  • Internal Use at Facebook: React was first used internally at Facebook to handle the increasing complexity of their web applications, particularly for the news feed.

  • Open Sourcing React: Facebook open-sourced React at the JavaScript Conference (JSConf) in May 2013. This marked the official release of React to the public.

  • Initial Skepticism: Initially, there was skepticism in the developer community, especially due to React’s use of JSX, which combines HTML with JavaScript, breaking the conventional separation of concerns.

  • React 0.9 to 0.14: React underwent significant improvements, including the introduction of features like the Virtual DOM and the ability to use React on the server side with Node.js.

  • React Native: In 2015, Facebook introduced React Native, a framework for building native mobile applications using React, which further boosted React’s popularity.

  • React 15: Released in April 2016, React 15 brought improvements to performance and the handling of SVG elements.

  • Create React App: Facebook released Create React App, a tool that simplifies the setup of a new React project, lowering the barrier to entry for new developers.

  • React Fiber: React 16, also known as React Fiber, was a complete rewrite of the React core algorithm, designed to improve the perceived performance of complex React applications.

  • Error Boundaries: React 16 introduced error boundaries, allowing developers to handle errors gracefully within their applications.

  • React Hooks: In 2019, React 16.8 introduced Hooks, a new way to manage state and side effects in functional components, which revolutionized how React applications were written.

  • Concurrent Mode: Concurrent Mode, though not fully released, was introduced as an experimental feature to improve the responsiveness of applications by allowing React to work on multiple tasks simultaneously.

  • React 17: Released in October 2020, React 17 focused on making it easier to upgrade React itself, rather than introducing new features. It was termed as a "stepping stone" release.

  • React 18: React 18 introduced features like automatic batching, streaming server rendering with Suspense, and the long-awaited Concurrent Mode, further enhancing the performance and capabilities of React applications.

  • React Ecosystem: Over the years, React's ecosystem has grown tremendously, with a vast array of libraries, tools, and extensions being developed by both the community and companies. Popular libraries like Redux, React Router, and Next.js have become essential tools in the React developer's toolkit.

  • Global Adoption: React has become one of the most widely used front-end libraries, powering applications from startups to tech giants like Facebook, Instagram, Airbnb, Uber, Netflix, and more.

Project setup

Install VSCode at VS Code

Install NodeJS at NodeJS

  • Create react app
    npx create-react-app my-app
  • Go to project directory.
    cd my-app
  • Start React app!
    npm start
  • Now edit App.js file and you should be able to see changes in app!

React Components

Class Components

In React, class components were the primary way to create components before the introduction of function components and hooks in React 16.8. Class components are ES6 classes that extend from React.Component and include a render method that returns React elements (which are typically JSX).

State management
1class MyComponent extends React.Component {
2  constructor(props) {
3    super(props);
4    this.state = {
5      count: 0,
6    };
7  }
8
9  render() {
10    return (
11      <div>
12        <p>Count: {this.state.count}</p>
13      </div>
14    );
15  }
16}
Lifecycle Methods
1class MyComponent extends React.Component {
2  componentDidMount() {
3    // Called once, after the component is inserted into the DOM
4  }
5
6  componentDidUpdate(prevProps, prevState) {
7    // Called after the component is updated
8  }
9
10  componentWillUnmount() {
11    // Called before the component is removed from the DOM
12  }
13
14  render() {
15    return <div>My Component</div>;
16  }
17}
Class Component Example
1import React from 'react';
2
3class Welcome extends React.Component {
4  constructor(props) {
5    super(props);
6    this.state = {
7      message: 'Welcome to React!',
8    };
9  }
10
11  changeMessage = () => {
12    this.setState({ message: 'You clicked the button!' });
13  };
14
15  render() {
16    return (
17      <div>
18        <h1>{this.state.message}</h1>
19        <button onClick={this.changeMessage}>Click Me</button>
20      </div>
21    );
22  }
23}
24
25export default Welcome;

Functional Components

With the introduction of hooks in React 16.8, function components became more powerful and allowed developers to manage state and use lifecycle methods without the need for class components. As a result, many developers now prefer function components for their simplicity and cleaner syntax, although class components are still widely used and supported.
1import React from 'react';
2
3function Welcome() {
4 
5  return (
6    <div>
7      Simple React Functional Component
8    </div>
9  );
10}
11
12export default Welcome;
Props Handling
1function Greeting(props) {
2  return <h1>Hello, {props.name}!</h1>;
3}
4
5// Usage
6<Greeting name="React" />
useState Hook
1import React, { useState } from 'react';
2
3function Counter() {
4  const [count, setCount] = useState(0);
5
6  return (
7    <div>
8      <p>You clicked {count} times</p>
9      <button onClick={() => setCount(count + 1)}>
10        Click me
11      </button>
12    </div>
13  );
14}
useEffect Hook
1import React, { useState, useEffect } from 'react';
2
3function Timer() {
4  const [count, setCount] = useState(0);
5
6  useEffect(() => {
7    const timer = setInterval(() => {
8      setCount(count + 1);
9    }, 1000);
10
11    return () => clearInterval(timer); // Cleanup on component unmount
12  }, [count]); // Dependency array
13
14  return <p>Timer: {count} seconds</p>;
15}

JSX in React

JSX (JavaScript XML) is a syntax extension for JavaScript used in React to describe what the UI should look like. It allows you to write HTML-like code within JavaScript, which React then transforms into JavaScript objects that represent the DOM elements. JSX is not mandatory in React, but it makes the code more readable and easier to write, especially for complex UIs.

Basic JSX Syntax

1const name = 'React';
2const element = <h1>Hello, {name}!</h1>;
3
4//JSX attributes are written in a camelCase style (
5const element = <img src="logo.png" alt="Logo" />;
6const elementWithExpression = <div style={{ color: 'blue' }}>Blue Text</div>;
7
8function greeting(user) {
9  if (user) {
10    return <h1>Hello, {user.name}!</h1>;
11  }
12  return <h1>Hello, Stranger!</h1>;
13}
14
15
16const element = (
17  <div>
18    <h1>Hello!</h1>
19    <p>Welcome to React.</p>
20  </div>
21);
22
23
24const user = {
25  firstName: 'John',
26  lastName: 'Doe',
27};
28const element = <h1>Hello, {user.firstName} {user.lastName}!</h1>;
29
30
31const isLoggedIn = true;
32const element = isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please sign in.</h1>;
33
34
35const items = ['Apple', 'Banana', 'Cherry'];
36const list = (
37  <ul>
38    {items.map((item, index) => <li key={index}>{item}</li>)}
39  </ul>
40);
41
42//fragments
43function FragmentExample() {
44  return (
45    <>
46      <h1>First Element</h1>
47      <p>Second Element</p>
48    </>
49  );
50}

Advanced JSX

1const props = { name: 'React', version: '17.0.2' };
2const element = <Component {...props} />;
3
4
5const element = (
6  <button onClick={() => alert('Clicked!')}>
7    Click Me
8  </button>
9);
10
11
12
13const isAdmin = true;
14const element = (
15  <div>
16    {isAdmin && <button>Delete User</button>}
17  </div>
18);
19
20
21const element = (
22  <div>
23    {/* This is a comment */}
24    <p>Hello, world!</p>
25  </div>
26);

JSX Transpilation

JSX is not valid JavaScript, so it needs to be transformed into JavaScript before it can be executed by the browser. This transformation is usually done by tools like Babel, which converts JSX into React.createElement calls.
1const element = <h1>Hello, world!</h1>;
2
3       //above statement gets transpiled to below code
4       //const element = React.createElement('h1', null, 'Hello, world!');

Managing State

Local State

We have already seen how to use useState hook to manage state of a component!

Derived State

Sometimes, the state of a component depends on the props or other pieces of state. This can be managed through derived state, which is calculated based on the current state and props.
1import React, { useState } from 'react';
2
3function Discount({ price }) {
4  const discount = price > 100 ? 10 : 0;
5  return (
6    <div>
7      <p>Price: ${price}</p>
8      <p>Discount: ${discount}</p>
9    </div>
10  );
11}
In this example, the discount is derived based on the price prop.

Managing state via useReducer

Complex state can be managed by useReducer. We will see how to use useReducer in upcoming sections!

Global State Management using context

In large applications, it is better to store the state of entire app globally using context api or state management library like redux, zustand, mobx etc. We will look at these techniques in upcoming sections.

Managing Props

Passing Props

Passing multiple props
1import React from 'react';
2
3function UserInfo(props) {
4  return (
5    <div>
6      <h2>{props.name}</h2>
7      <p>Age: {props.age}</p>
8      <p>Email: {props.email}</p>
9    </div>
10  );
11}
12
13function App() {
14  return (
15    <div>
16      <UserInfo name="Alice" age={25} email="[email protected]" />
17      <UserInfo name="Bob" age={30} email="[email protected]" />
18    </div>
19  );
20}
21
22export default App;
Passing Callback Functions as Props
1import React from 'react';
2
3function Button(props) {
4  return <button onClick={props.onClick}>{props.label}</button>;
5}
6
7function App() {
8  const handleClick = () => {
9    alert('Button clicked!');
10  };
11
12  return (
13    <div>
14      <Button label="Click Me" onClick={handleClick} />
15    </div>
16  );
17}
18
19export default App;
Passing children props
1import React from 'react';
2
3function Card(props) {
4  return (
5    <div className="card">
6      <div className="card-content">{props.children}</div>
7    </div>
8  );
9}
10
11function App() {
12  return (
13    <div>
14      <Card>
15        <h2>Card Title</h2>
16        <p>This is the content of the card.</p>
17      </Card>
18    </div>
19  );
20}
21
22export default App;

Default Props

1import React from 'react';
2
3function Greeting(props) {
4  return <h1>Hello, {props.name}!</h1>;
5}
6
7Greeting.defaultProps = {
8  name: 'Guest'
9};
10
11function App() {
12  return (
13    <div>
14      <Greeting />
15      <Greeting name="Eve" />
16    </div>
17  );
18}
19
20export default App;

Prop Drilling

When multiple components need to share the same state, it's common to "lift" the state up to the closest common ancestor and pass it down as props.This is called as prop drilling.
1import React, { useState } from 'react';
2
3function TemperatureInput({ temperature, onTemperatureChange }) {
4  return (
5    <div>
6      <input
7        type="text"
8        value={temperature}
9        onChange={(e) => onTemperatureChange(e.target.value)}
10      />
11    </div>
12  );
13}
14
15function Calculator() {
16  const [temperature, setTemperature] = useState('');
17
18  return (
19    <div>
20      <TemperatureInput
21        temperature={temperature}
22        onTemperatureChange={setTemperature}
23      />
24    </div>
25  );
26}
Here, the temperature state is lifted to the Calculator component, and TemperatureInput receives it as a prop.

React Lifecycle Methods

Mounting (ComponentDidMount Equivalent)

To run code when the component is first added to the DOM, use the useEffect hook with an empty dependency array.
1import React, { useEffect } from 'react';
2
3function MyComponent() {
4  useEffect(() => {
5    console.log('Component Mounted');
6    // Fetch data or perform an action when the component mounts
7
8    return () => {
9      // Cleanup code when the component unmounts
10      console.log('Component Unmounted');
11    };
12  }, []); // Empty dependency array ensures this runs only once (on mount)
13
14  return <div>Hello, World!</div>;
15}

Updating (ComponentDidUpdate and ComponentDidMount Equivalent)

To run code after the component updates, you can use the useEffect hook with specific dependencies (props or state). The effect will run when any of the dependencies change.
1import React, { useState, useEffect } from 'react';
2
3function MyComponent() {
4  const [count, setCount] = useState(0);
5
6  useEffect(() => {
7    console.log('Component Updated: Count is', count);
8    // Perform an action when 'count' changes
9  }, [count]); // Only re-run the effect when 'count' changes
10
11  return (
12    <div>
13      <p>Count: {count}</p>
14      <button onClick={() => setCount(count + 1)}>Increment</button>
15    </div>
16  );
17}

Unmounting (ComponentWillUnmount Equivalent)

To perform cleanup or other actions when the component is about to be removed from the DOM, use the return statement in useEffect to provide a cleanup function.
1import React, { useEffect } from 'react';
2
3function MyComponent() {
4  useEffect(() => {
5    const timer = setInterval(() => {
6      console.log('Timer running...');
7    }, 1000);
8
9    // Cleanup on unmount
10    return () => {
11      clearInterval(timer);
12      console.log('Component Unmounted');
13    };
14  }, []); // Empty dependency array means this effect runs only on mount/unmount
15
16  return <div>Check your console</div>;
17}

Skipping Effects on the Initial Render

Sometimes, you only want to run an effect when a specific value changes, not on the initial render. You can handle this by checking if the component has mounted using a ref.
1import React, { useState, useEffect, useRef } from 'react';
2
3function MyComponent({ prop }) {
4  const hasMounted = useRef(false);
5
6  useEffect(() => {
7    if (hasMounted.current) {
8      console.log('Prop updated:', prop);
9    } else {
10      hasMounted.current = true;
11    }
12  }, [prop]);
13
14  return <div>{prop}</div>;
15}

Hooks in React

useState

We have already seen this hook earlier!

useEffect

We have already seen this hook earlier! But here is another example.
1import React, { useState, useEffect } from 'react';
2
3function Timer() {
4  const [time, setTime] = useState(0);
5
6  useEffect(() => {
7    const interval = setInterval(() => {
8      setTime((prevTime) => prevTime + 1);
9    }, 1000);
10
11    return () => clearInterval(interval); // Cleanup the interval on component unmount
12  }, []); // Empty dependency array means this effect runs only on mount/unmount
13
14  return <div>Time: {time}s</div>;
15}

useReducer

useReducer is useful when you have complex state logic that involves multiple sub-values or when the next state depends on the previous state. It is a good alternative to useState when dealing with more intricate state management within a specific component
1import React, { useReducer } from 'react';
2
3// Define the initial state of the counter
4const initialState = { count: 0 };
5
6// Define a reducer function that will handle the actions
7function reducer(state, action) {
8  switch (action.type) {
9    case 'increment':
10      return { count: state.count + 1 };
11    case 'decrement':
12      return { count: state.count - 1 };
13    case 'reset':
14      return initialState;
15    default:
16      throw new Error();
17  }
18}
19
20function Counter() {
21  // useReducer returns the current state and a dispatch function
22  const [state, dispatch] = useReducer(reducer, initialState);
23
24  return (
25    <div>
26      <p>Count: {state.count}</p>
27      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
28      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
29      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
30    </div>
31  );
32}
33
34export default Counter;

useContex hook

We will look at this hook in upcoming sections!

useRef

The useRef hook lets you persist values across renders without causing a re-render, often used for accessing DOM elements directly.
1import React, { useRef } from 'react';
2
3function TextInputWithFocusButton() {
4  const inputEl = useRef(null);
5
6  const handleClick = () => {
7    inputEl.current.focus();
8  };
9
10  return (
11    <div>
12      <input ref={inputEl} type="text" />
13      <button onClick={handleClick}>Focus the input</button>
14    </div>
15  );
16}

useMemo

The useMemo hook returns a memoized value, useful for expensive calculations that shouldn't be re-run on every render.
1import React, { useState, useMemo } from 'react';
2
3function ExpensiveCalculationComponent({ num }) {
4  const calculateFactorial = (n) => {
5    console.log('Calculating factorial...');
6    if (n <= 1) return 1;
7    return n * calculateFactorial(n - 1);
8  };
9
10  const factorial = useMemo(() => calculateFactorial(num), [num]);
11
12  return <div>Factorial of {num} is {factorial}</div>;
13}
14
15function App() {
16  const [num, setNum] = useState(5);
17
18  return (
19    <div>
20      <ExpensiveCalculationComponent num={num} />
21      <button onClick={() => setNum(num + 1)}>Increase Number</button>
22    </div>
23  );
24}

useCallback

The useCallback hook returns a memoized version of the callback function, useful to prevent functions from being re-created on every render.
1import React, { useState, useCallback } from 'react';
2
3function ChildComponent({ onClick }) {
4  return <button onClick={onClick}>Click me</button>;
5}
6
7function ParentComponent() {
8  const [count, setCount] = useState(0);
9
10  const handleClick = useCallback(() => {
11    setCount(count + 1);
12  }, [count]);
13
14  return (
15    <div>
16      <p>Count: {count}</p>
17      <ChildComponent onClick={handleClick} />
18    </div>
19  );
20}

useLayoutEffect

The useLayoutEffect hook is similar to useEffect, but it fires synchronously after all DOM mutations. Use it when you need to perform actions that affect the layout of your component.
1import React, { useState, useLayoutEffect, useRef } from 'react';
2
3function LayoutEffectComponent() {
4  const [value, setValue] = useState(0);
5  const divRef = useRef(null);
6
7  useLayoutEffect(() => {
8    if (divRef.current) {
9      divRef.current.style.transform = `translateX(${value * 10}px)`;
10    }
11  }, [value]);
12
13  return (
14    <div>
15      <div ref={divRef} style={{ width: 100, height: 100, background: 'lightblue' }} />
16      <button onClick={() => setValue(value + 1)}>Move Right</button>
17    </div>
18  );
19}

useImperativeHandle

The useImperativeHandle hook customizes the instance value that is exposed to parent components when using ref. It's rarely used but can be useful in specific scenarios.
1import React, { useImperativeHandle, forwardRef, useRef } from 'react';
2
3const CustomInput = forwardRef((props, ref) => {
4  const inputRef = useRef();
5
6  useImperativeHandle(ref, () => ({
7    focus: () => {
8      inputRef.current.focus();
9    },
10    clear: () => {
11      inputRef.current.value = '';
12    }
13  }));
14
15  return <input ref={inputRef} {...props} />;
16});
17
18function App() {
19  const inputRef = useRef();
20
21  return (
22    <div>
23      <CustomInput ref={inputRef} />
24      <button onClick={() => inputRef.current.focus()}>Focus</button>
25      <button onClick={() => inputRef.current.clear()}>Clear</button>
26    </div>
27  );
28}

useDebugValue

The useDebugValue hook is used to display a label in React DevTools, useful for custom hooks.
1import React, { useState, useDebugValue } from 'react';
2
3function useCustomHook(initialValue) {
4  const [value, setValue] = useState(initialValue);
5  useDebugValue(value > 5 ? 'High' : 'Low');
6  return [value, setValue];
7}
8
9function App() {
10  const [count, setCount] = useCustomHook(0);
11
12  return (
13    <div>
14      <p>Count: {count}</p>
15      <button onClick={() => setCount(count + 1)}>Increment</button>
16    </div>
17  );
18}

Routing with React Router

React Router is a popular library for handling routing in React applications. It allows you to define different routes in your application, enabling navigation between different components or views without requiring a full page refresh.

Key Concepts in React Router
  • Router: The top-level component that enables routing in your application. There are different types of routers available - BrowserRouter and HashRouter. BrowserRouter uses the HTML5 history API (pushState, replaceState) to keep your UI in sync with the URL. HashRouter ses the URL hash (#) to keep your UI in sync with the URL.
  • Route: Defines the mapping between a URL path and a component. When the URL matches the path, the component is rendered.
  • Switch: Renders the first child Route or Redirect that matches the location.
  • Link: Used to create navigational links in your application. It's similar to an anchor (a) tag in HTML.
  • NavLink: Similar to Link, but with additional styling capabilities when the link is active.

Basic Routing

1import React from 'react';
2import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
3
4function Home() {
5  return <h2>Home</h2>;
6}
7
8function About() {
9  return <h2>About</h2>;
10}
11
12function Contact() {
13  return <h2>Contact</h2>;
14}
15
16function App() {
17  return (
18    <Router>
19      <nav>
20        <ul>
21          <li><Link to="/">Home</Link></li>
22          <li><Link to="/about">About</Link></li>
23          <li><Link to="/contact">Contact</Link></li>
24        </ul>
25      </nav>
26
27      <Switch>
28        <Route path="/" exact component={Home} />
29        <Route path="/about" component={About} />
30        <Route path="/contact" component={Contact} />
31      </Switch>
32    </Router>
33  );
34}
35
36export default App;

Nested Routes

React Router also supports nested routing, where routes can be defined within other components, allowing for more complex routing structures.
1import React from 'react';
2import { BrowserRouter as Router, Route, Link, useRouteMatch } from 'react-router-dom';
3
4function Topics() {
5  let { path, url } = useRouteMatch();
6
7  return (
8    <div>
9      <h2>Topics</h2>
10      <ul>
11        <li>
12          <Link to={`${url}/react`}>React</Link>
13        </li>
14        <li>
15          <Link to={`${url}/redux`}>Redux</Link>
16        </li>
17        <li>
18          <Link to={`${url}/router`}>React Router</Link>
19        </li>
20      </ul>
21
22      <Route path={`${path}/:topicId`} component={Topic} />
23    </div>
24  );
25}
26
27function Topic({ match }) {
28  return <h3>Requested topic ID: {match.params.topicId}</h3>;
29}
30
31function App() {
32  return (
33    <Router>
34      <div>
35        <nav>
36          <ul>
37            <li><Link to="/">Home</Link></li>
38            <li><Link to="/topics">Topics</Link></li>
39          </ul>
40        </nav>
41
42        <Switch>
43          <Route path="/" exact>
44            <h2>Home</h2>
45          </Route>
46          <Route path="/topics" component={Topics} />
47        </Switch>
48      </div>
49    </Router>
50  );
51}
52
53export default App;

Route Parameters

React Router allows dynamic routing with parameters. These parameters can be accessed within the component using match.params.
1<Route path="/users/:userId" component={User} />
2
3function User({ match }) {
4  return <h2>User ID: {match.params.userId}</h2>;
5}

Redirects

You can redirect to another route using the Redirect component.
1import { Redirect } from 'react-router-dom';
2
3function OldPage() {
4  return <Redirect to="/new-page" />;
5}

Programmatic Navigation

You can navigate programmatically using the useHistory hook.
1import { useHistory } from 'react-router-dom';
2
3function MyComponent() {
4  let history = useHistory();
5
6  const handleClick = () => {
7    history.push('/new-page');
8  };
9
10  return <button onClick={handleClick}>Go to new page</button>;
11}

React Context API

The React Context API is a powerful feature that allows you to share state and other data across your component tree without having to pass props down manually at every level. It's particularly useful for managing global state, themes, user authentication, and more in a React application.

Key Concepts in Context API

  • Context Creation: You create a context using React.createContext(). This function returns an object with two components: Provider: A component that provides the context value to its children. Consumer: A component that consumes the context value.
  • Provider Component: The Provider component is used to wrap the part of your component tree that needs access to the context. It accepts a value prop, which represents the data that you want to share.
  • Consumer Component: The Consumer component is used to access the context value. It requires a function as a child, which receives the context value as an argument.
  • useContext Hook: The useContext hook is a simpler and more modern way to consume context values in functional components without using the Consumer component.

Context API Example

Creating Context
1import React, { createContext, useState } from 'react';
2
3// Create a Context for the theme
4const ThemeContext = createContext();
5
6export const ThemeProvider = ({ children }) => {
7  // State to hold the current theme
8  const [theme, setTheme] = useState('light');
9
10  // Function to toggle between light and dark themes
11  const toggleTheme = () => {
12    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
13  };
14
15  return (
16    <ThemeContext.Provider value={{ theme, toggleTheme }}>
17      {children}
18    </ThemeContext.Provider>
19  );
20};
21
22export default ThemeContext;
Consuming the Context in a Functional Component
1import React, { useContext } from 'react';
2import ThemeContext from './ThemeContext';
3
4const ThemedComponent = () => {
5  const { theme, toggleTheme } = useContext(ThemeContext);
6
7  return (
8    <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
9      <p>The current theme is {theme}</p>
10      <button onClick={toggleTheme}>Toggle Theme</button>
11    </div>
12  );
13};
14
15export default ThemedComponent;
Using the Provider in the App
1import React from 'react';
2import { ThemeProvider } from './ThemeContext';
3import ThemedComponent from './ThemedComponent';
4
5const App = () => {
6  return (
7    <ThemeProvider>
8      <ThemedComponent />
9    </ThemeProvider>
10  );
11};
12
13export default App;
Here is how above example works.
  • ThemeContext: We created a ThemeContext using createContext(). This context will hold the theme state and a function to toggle the theme.
  • ThemeProvider: The ThemeProvider component wraps the application (or part of it) and provides the theme and toggle function to all components within it.
  • useContext Hook: In ThemedComponent, we use the useContext hook to access the current theme and the function to toggle it. The component's background and text color change based on the current theme.
  • Provider Usage: In the App component, ThemeProvider wraps ThemedComponent, ensuring that the theme state is available throughout the component tree.

State Management with Redux

Redux is a popular state management library for JavaScript applications, particularly for React. It provides a centralized place to store and manage the state of your entire application, enabling predictable and consistent state management across your app.

Key Concepts in Redux

  • Store: The store is the central repository that holds the entire state of your application. It is a single JavaScript object that manages the state and can be accessed by any component in your application.
  • Actions: Actions are plain JavaScript objects that describe an event or change that has occurred in the application. Each action must have a type property (a string constant) that indicates the type of action being performed. Actions can also contain additional data (payload) related to that event.
  • Reducers: Reducers are pure functions that take the current state and an action as arguments and return a new state. The reducer function determines how the state should change in response to a given action.
  • Dispatch: dispatch is a function provided by the store that allows you to send actions to the store. When an action is dispatched, it triggers the reducer to calculate the new state based on the current state and the action.
  • Selectors: Selectors are functions that extract specific pieces of data from the store. They help in retrieving data from the store in a more organized and reusable way.
  • Middleware: Middleware allows you to extend Redux with custom functionality. Common use cases for middleware include handling asynchronous actions, logging, and error reporting.

Redux Example

Install redux
npm install redux react-redux
Create redux store
1import { createStore } from 'redux';
2
3// Define action types
4const INCREMENT = 'INCREMENT';
5const DECREMENT = 'DECREMENT';
6
7// Define action creators
8const increment = () => ({ type: INCREMENT });
9const decrement = () => ({ type: DECREMENT });
10
11// Define the initial state
12const initialState = {
13  count: 0
14};
15
16// Define the reducer
17const counterReducer = (state = initialState, action) => {
18  switch (action.type) {
19    case INCREMENT:
20      return { ...state, count: state.count + 1 };
21    case DECREMENT:
22      return { ...state, count: state.count - 1 };
23    default:
24      return state;
25  }
26};
27
28// Create the Redux store
29const store = createStore(counterReducer);
30
31export { store, increment, decrement };
Connect redux with react
1import React from 'react';
2import { useSelector, useDispatch } from 'react-redux';
3import { increment, decrement } from './store';
4
5const Counter = () => {
6  const count = useSelector((state) => state.count);
7  const dispatch = useDispatch();
8
9  return (
10    <div>
11      <h1>Count: {count}</h1>
12      <button onClick={() => dispatch(increment())}>Increment</button>
13      <button onClick={() => dispatch(decrement())}>Decrement</button>
14    </div>
15  );
16};
17
18export default Counter;
Wrap app with provider
1import React from 'react';
2import ReactDOM from 'react-dom';
3import { Provider } from 'react-redux';
4import { store } from './store';
5import Counter from './Counter';
6
7const App = () => (
8  <Provider store={store}>
9    <Counter />
10  </Provider>
11);
12
13ReactDOM.render(<App />, document.getElementById('root'));

React 19 features