Skip to content

A beginner-friendly repository to learn React with TypeScript, featuring clean code, reusable components, and TypeScript best practices. Perfect for building scalable, type-safe React applications while mastering essential development concepts.

Notifications You must be signed in to change notification settings

RyomenDev/react-ts-base

Repository files navigation

Learning TypeScript

This repository contains various examples and exercises to help you learn TypeScript, with a focus on React concepts and features. The following topics are covered:

  • Class Components
  • Props and Component as Props
  • React Hooks (useState, useReducer, useRef)
  • Context API
  • Custom Components
  • Generics and Polymorphic Components
  • Restricting Props
  • Template Literals in TypeScript

Table of Contents

Class Components

Class components in React are ES6 classes that extend React.Component. Here is an example:

import React, { Component } from 'react';

interface MyComponentProps {
  message: string;
}

class MyComponent extends Component<MyComponentProps> {
  render() {
    return <h1>{this.props.message}</h1>;
  }
}

Props and Component as Props

Props are used to pass data into a component. A component can also accept other components as props.

Example of passing data as props:

interface MyComponentProps {
  message: string;
}

const MyComponent = ({ message }: MyComponentProps) => {
  return <h1>{message}</h1>;
};

Passing a component as a prop:

interface ButtonProps {
  label: string;
  onClick: () => void;
}

const Button: React.FC<ButtonProps> = ({ label, onClick }) => (
  <button onClick={onClick}>{label}</button>
);

const Parent = () => {
  return (
    <Button label="Click Me" onClick={() => alert('Button clicked!')} />
  );
};

React Hooks

useState

The useState hook allows you to add state to functional components.

import React, { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

useReducer

useReducer is similar to useState but gives you more control over state updates, ideal for complex state logic.

import React, { useReducer } from 'react';

const reducer = (state: number, action: string): number => {
  switch (action) {
    case 'increment':
      return state + 1;
    case 'decrement':
      return state - 1;
    default:
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, 0);

  return (
    <div>
      <p>Count: {state}</p>
      <button onClick={() => dispatch('increment')}>Increment</button>
      <button onClick={() => dispatch('decrement')}>Decrement</button>
    </div>
  );
};

useRef

The useRef hook allows you to persist values between renders without triggering re-renders.

import React, { useRef } from 'react';

const FocusInput = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleFocus = () => {
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <div>
      <input ref={inputRef} />
      <button onClick={handleFocus}>Focus the input</button>
    </div>
  );
};

Context API

The Context API allows you to share state across your component tree without passing props down manually.

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

const ThemeContext = createContext('light');

const App = () => {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
      <ChildComponent />
    </ThemeContext.Provider>
  );
};

const ChildComponent = () => {
  const theme = useContext(ThemeContext);
  return <div>The current theme is {theme}</div>;
};

Custom Components

Custom components are React components that you create to encapsulate specific logic or UI elements.

interface CardProps {
  title: string;
  content: string;
}

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

const App = () => (
  <Card title="Card Title" content="This is the content of the card." />
);

Generics and Polymorphic Components

Generics allow you to define components that work with a variety of types.

interface ButtonProps<T> {
  label: string;
  onClick: (value: T) => void;
}

const Button = <T,>({ label, onClick }: ButtonProps<T>) => {
  return <button onClick={() => onClick('clicked' as T)}>{label}</button>;
};

const App = () => {
  const handleClick = (value: string) => alert(value);
  return <Button label="Click Me" onClick={handleClick} />;
};

Restricting Props

You can restrict the values that a prop can accept using TypeScript types.

interface ButtonProps {
  type: 'button' | 'submit' | 'reset';
}

const Button = ({ type }: ButtonProps) => (
  <button type={type}>Click Me</button>
);

Template Literals

Template literals allow you to embed expressions within string literals.

const name = 'John';
const greeting = `Hello, ${name}! Welcome to TypeScript.`;

console.log(greeting); // Output: Hello, John! Welcome to TypeScript.

About

A beginner-friendly repository to learn React with TypeScript, featuring clean code, reusable components, and TypeScript best practices. Perfect for building scalable, type-safe React applications while mastering essential development concepts.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published