DEV Community


[TypeScript][Express] Try React

Masui Masanori
Programmer, husband, father I love C#, TypeScript, etc.
・3 min read


This time, I will tye React to get and show book data from the Express application.


  • Node.js ver.16.5.0
  • create-react-app ver.4.0.3
  • React ver.17.0.2
  • react-router-dom ver.5.2.0
  • TypeScript ver.4.3.5
  • ESLint ver.7.30.0

According to the tutorials, I created a React project by create-react-app.

npx create-react-app bookstore-sample-client --template typescript
Enter fullscreen mode Exit fullscreen mode

Use ESLint

This time, I also try using ESLint.

npx eslint --init
Enter fullscreen mode Exit fullscreen mode

And I got errors in TSX files.

'React' must be in scope when using JSX
Enter fullscreen mode Exit fullscreen mode

According to some posts, I add a rule in .eslitrc.yml


  browser: true
  es2021: true
  - 'eslint:recommended'
  - 'plugin:react/recommended'
  - 'plugin:@typescript-eslint/recommended'
parser: '@typescript-eslint/parser'
    jsx: true
  ecmaVersion: 12
  sourceType: module
  - react
  - '@typescript-eslint'
rules: {
  "react/react-in-jsx-scope": "off",
Enter fullscreen mode Exit fullscreen mode


Although I just add only one page in this sample, I try routing as a SPA by "react-router-dom".

[Client] App.tsx

import './App.css';
import {
  BrowserRouter as Router,
} from "react-router-dom";
import { SearchBooks } from './search/SearchBooks';

function App(): JSX.Element {
  return (
              <Link to="/">Home</Link>
          <Route path="/">
            <SearchBooks />
export default App;
Enter fullscreen mode Exit fullscreen mode

[Express] Use CORS

Because the domains aren't same as the Express app and the React app, I have to allow origins in the Express app.

[Server] index.ts

import "reflect-metadata";
import express from 'express';
import cors from 'cors';
import { container } from 'tsyringe';
import { BookService } from "./books/bookService";

const port = 3099;
const app = express();

const allowlist = ['http://localhost:3000', 'http://localhost:3099']
const corsOptionsDelegate: cors.CorsOptionsDelegate<any> = (req, callback) => {
  const corsOptions = (allowlist.indexOf(req.header('Origin')) !== -1)? { origin: true }: { origin: false };
  callback(null, corsOptions);
app.get('/books', cors(corsOptionsDelegate), async (req, res) => {
    const books = container.resolve(BookService);
    res.json(await books.getBooks());

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
Enter fullscreen mode Exit fullscreen mode

[Client] BookAccessor.ts

import { Book } from "../models/book";

export async function search(): Promise<Book[]> {    
    return await fetch('http://localhost:3099/books', {
        method: 'GET',
    .then(response => response.json())
    .then(json => JSON.parse(JSON.stringify(json)))
    .catch(err => console.error(err));
Enter fullscreen mode Exit fullscreen mode

Create pages

This time, I just add simple pages.

[Client] SearchBooks.tsx

import { useState } from "react";
import './SearchBooks.css';
import { Book } from "../models/book";
import { SearchBookRow } from "./SearchBookRow";
import * as bookAccessor from './BookAccessor';

export function SearchBooks(): JSX.Element {
    const [books, setBooks] = useState([] as Array<Book>);
    const generateRows = () => {
        const contents: JSX.Element[] = [];
        for(const b of books) {
            contents.push(<SearchBookRow key={} book={b}></SearchBookRow>);
        return contents;
    return <div className="search_result_area">
        <button onClick={async () => {
Enter fullscreen mode Exit fullscreen mode

[Client] SearchBooks.css

.search_result_row {
    background-color: aqua;
Enter fullscreen mode Exit fullscreen mode

[Client] SearchBookRow.tsx

import { Book } from "../models/book";

export type SearchBookRowProps = {
    book: Book
export function SearchBookRow(props: SearchBookRowProps): JSX.Element {

    return <div className="search_result_row">
        <div className="search_result_row_cell">{}</div>
        <div className="search_result_row_cell">{}</div>
        <div className="search_result_row_cell">{}</div>
        <div className="search_result_row_cell">{}</div>
Enter fullscreen mode Exit fullscreen mode


According to the result, the CSS class names what are generated from "className" won't be changed automatically.
So I can write child components' CSS in parent's CSS like the sample.

If I add same CSS code in child components' CSS files, the child components use them.

Discussion (0)