DEV Community

Cover image for React with Typescript
jean luc tuyishime
jean luc tuyishime

Posted on

React with Typescript

We will build a simple app for inviting people to our event.

1. To start a new Create React App project with TypeScript, you can run:

npx create-react-app my-app --template typescript

# or

yarn create react-app my-app --template typescript
Enter fullscreen mode Exit fullscreen mode

2. Define type definition for our state
In our App.tsx file we can define the type definition

import React, { useState } from "react";
import List from "./components/List";
import "./App.css";
import AddToList from "./components/AddToList";

// Type definition
export interface IState {
  people: {
    name: string;
    age: number;
    url: string;
    {/* The question mark is used to mark that variable as an 
       optional variable */}
    note?: string;
  }[];
}

function App() {
  // we can pass our interface to our useState
  const [people, setPeople] = useState<IState["people"]>([
    {
      name: "Jean Luc Tuyishime",
      url: "https://cdn.nba.com/headshots/nba/latest/1040x760/2544.png",
      age: 44,
      note: "Lorem ipsum dollar sit amet",
    },
  ]);

  return (
    <div className="App">
      <p>people invited to my party</p>
      <List people={people} />
      <AddToList people={people} setPeople={setPeople} />
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

We have also imported two files List.tsx and AddToList.tsx and passed people and setPeople as props.

3. In our List.tsx file
we can import and pass props with typescript

import React from "react";
import { IState as IProps } from "../App";

// Pass props with typescript
const List: React.FC<IProps> = ({ people }) => {
 {/* Here we are returning a JSX element */}
  const renderList = (): JSX.Element[] => {
    return people.map((person) => {
      return (
        <li className="List">
          <div className="List-header">
            <img className="List-img" src={person.url} />
            <h2>{person.name}</h2>
          </div>
          <p>{person.age} years old</p>
          <p className="List-note">{person.note}</p>
        </li>
      );
    });
  };
  return <div>{renderList()}</div>;
};

export default List;
Enter fullscreen mode Exit fullscreen mode

4. In our AddToList.tsx file

import React, { useState } from "react";
import { IState as Props } from "../App";

// Type definition for our state (people) passed as props.
interface IProps {
  people: Props["people"];
  setPeople: React.Dispatch<React.SetStateAction<Props["people"]>>;
}

const AddToList: React.FC<IProps> = ({ people, setPeople }) => {
  const [input, setInput] = useState({
    name: "",
    age: "",
    note: "",
    img: "",
  });

// type definition for our event => (e). 
  const handleChange = (
    e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
  ): void => {
    setInput({
      ...input,
      [e.target.name]: e.target.value,
    });
  };

  // void is used here because we are not returning any value
  const handleClick = (): void => {
    if (!input.name || !input.age || !input.img) return;
    setPeople([
      ...people,
      {
        name: input.name,
        age: parseInt(input.age),
        note: input.note,
        url: input.img,
      },
    ]);

    setInput({
      name: "",
      age: "",
      note: "",
      img: "",
    });
  };

  return (
    <div className="AddToList">
      Add To List Component
      <input
        type="text"
        placeholder="Name"
        value={input.name}
        className="AddToList-input"
        onChange={handleChange} 
        name="name"
      />
      <input
        type="text"
        placeholder="Age"
        value={input.age}
        className="AddToList-input"
        onChange={handleChange}
        name="age"
      />
      <input
        type="text"
        placeholder="Image Url"
        value={input.img}
        className="AddToList-input"
        onChange={handleChange}
        name="img"
      />
      <textarea
        placeholder="Notes"
        value={input.note}
        className="AddToList-input"
        onChange={handleChange}
        name="note"
      />
      <button onClick={handleClick} className="AddToList-btn">
        Add To List
      </button>
    </div>
  );
};

export default AddToList;

Enter fullscreen mode Exit fullscreen mode

Discussion (0)