The following is a detailed expansion of the React + TypeScript development guide, designed to help React beginners gain a deeper understanding of each core concept, and to provide specific examples and explanations of TypeScript features.

1. React Basic Concepts

Components

The core idea of React is to break down UI into reusable components. Components can be function components or class components, but modern React recommends function components because they are more concise and work better with Hooks.

  • Function Components: When using TypeScript, you can define component types using React.FC (short for FunctionComponent). React.FC implicitly includes the type of children.
  • Props: Components receive external data through props. TypeScript requires defining types for props.

Detailed Example:


import React from 'react';

// Define Props type
interface GreetingProps {
  name: string;
  age?: number; // Optional property
}

// Use React.FC to define component
const Greeting: React.FC<GreetingProps> = ({ name, age }) => {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      {age && <p>You are {age} years old.</p>}
    </div>
  );
};

// Use component
const App: React.FC = () => {
  return <Greeting name="Alice" age={25} />;
};

Notes:

  • React.FC is not mandatory; you can also use a regular function with type annotation: (props: GreetingProps) => JSX.Element.
  • Try to keep components simple, with single responsibility, for easier reuse.

2. React Hooks

Hooks are the core tools of React function components, allowing you to manage state and side effects without using classes.

useState

Used to manage a component’s local state.

Detailed Example:


import { useState } from 'react';

const Counter: React.FC = () => {
  const [count, setCount] = useState<number>(0); // Specify state type

  const increment = () => setCount(prev => prev + 1);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Add</button>
    </div>
  );
};

Type inference: TypeScript can usually infer types, but complex states (like objects) need to be explicitly defined:

interface User {
  name: string;
  age: number;
}
const [user, setUser] = useState<User>({ name: '', age: 0 });

useEffect

Used to handle side effects, such as data fetching, subscriptions, or DOM operations.

Detailed Example:


import { useEffect, useState } from 'react';

const DataFetcher: React.FC = () => {
  const [data, setData] = useState<string[]>([]);
  const [loading, setLoading] = useState<boolean>(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/data');
        const result: string[] = await response.json();
        setData(result);
      } catch (error) {
        console.error('Error fetching data:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []); // Empty dependency array, only runs on mount

  if (loading) return <p>Loading...</p>;
  return (
    <ul>
      {data.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
};

Cleaning up side effects: If you have subscriptions or timers, remember to return a cleanup function:


useEffect(() => {
  const timer = setInterval(() => console.log('Tick'), 1000);
  return () => clearInterval(timer); // Clean up when component unmounts
}, []);

useContext

Used to share global state in the component tree, avoiding prop drilling.

Detailed Example:

import { createContext, useContext, useState } from 'react';

// Define Context type
interface ThemeContextType {
  theme: 'light' | 'dark';
  toggleTheme: () => void;
}

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

const App: React.FC = () => {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');
  const toggleTheme = () => setTheme(prev => (prev === 'light' ? 'dark' : 'light'));

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <ThemedComponent />
    </ThemeContext.Provider>
  );
};

const ThemedComponent: React.FC = () => {
  const context = useContext(ThemeContext);
  if (!context) throw new Error('ThemedComponent must be used within ThemeContext.Provider');
  const { theme, toggleTheme } = context;

  return (
    <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
      <p>Current theme: {theme}</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
};

3. TypeScript and React Integration

Type Definitions

The core advantage of TypeScript is providing type checking for variables, functions, props, etc.

Props Types:

interface CardProps {
  title: string;
  content: string;
  onClick?: (event: React.MouseEvent<HTMLDivElement>) => void; // Optional event
}

const Card: React.FC<CardProps> = ({ title, content, onClick }) => (
  
  <div onClick={onClick}>
    <h2>{title}</h2>
    <p>{content}</p>
  </div>
  
);

Event Types:

const Input: React.FC = () => {
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
  };

  return <input type="text" onChange={handleChange} />;
};

Interfaces and Types

Interfaces: Suitable for object structures, support extension.

interface User {
  id: number;
  name: string;
}
interface Admin extends User {
  role: string;
}

Type Aliases: More flexible, support union types.

type Status = 'idle' | 'loading' | 'success' | 'error';
const [status, setStatus] = useState<Status>('idle');

Generics

In custom Hooks or components, generics improve code reusability.

Detailed Example (Custom Hook):

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);

  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(setData);
  }, [url]);

  return data;
}

const UserList: React.FC = () => {
  interface User { id: number; name: string }
  const users = useFetch<User[]>('https://api.example.com/users');
  return <ul>{users?.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
};

4. Component Lifecycle

Modern React uses Hooks to simulate lifecycle:

Mounting:

useEffect(() => {
  console.log('Component mounted');
}, []);

Updating:

useEffect(() => {
  console.log('Count updated:', count);
}, [count]);

Unmounting:

useEffect(() => {
  const subscription = subscribeToSomething();
  return () => {
    subscription.unsubscribe();
    console.log('Component unmounted');
  };
}, []);

5. Routing (React Router)

React Router is a routing solution for single-page applications.

Detailed Example:


import { BrowserRouter, Route, Routes, Link } from 'react-router-dom';

const Home: React.FC = () => <h1>Home Page</h1>;
const About: React.FC = () => <h1>About Page</h1>;

const App: React.FC = () => (
  <BrowserRouter>
    <nav>
      <Link to="/">Home</Link> | <Link to="/about">About</Link>
    </nav>
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
  </BrowserRouter>
);

Dynamic Routing:


<Route path="/user/:id" element={<UserProfile />} />

const UserProfile: React.FC = () => {
  const { id } = useParams<{ id: string }>(); // Type annotation
  return <p>User ID: {id}</p>;
};

6. State Management

Simple State

Use useState and useContext.

Complex State (Redux Toolkit)

Installation:

```

Comments