スキップしてメイン コンテンツに移動

[TypeScript] Try React + Hooks

Intro

In this time, I tried Hooks. [TypeScript] Try React 1 [TypeScript] Try React + Redux

Try Hooks

Introducing Hooks – React According to the documents, Hooks were for using states and side-effects in function components.

State

"useStates" gave me current states and functions what create next states like Reducer of Redux.

App.tsx


import 'raf/polyfill';
import React, { useState, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
import { renderBoard } from './tic-tac-toe-hooks/BoardHook';
import { BoardState } from './tic-tac-toe/Board';

function App() {
    // default value and the "state" type came from the argument of "useState". 
  const [state, setBoardState] = useState(initialState());

  function updateSquareValues(key: number) {
    const lastSquares = state.squares.slice();
    lastSquares[key] = (state.nextIsX)? '✕': '◯';
    
    // update "state"
    setBoardState({
      nextIsX: ! state.nextIsX,
      squares: lastSquares
    });
  
  }
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div>next player: {(state.nextIsX)? '✕': '◯'}</div>
        {renderBoard({state, onValueChange: updateSquareValues })}
      </header>
    </div>
  );
}
function initialState(): BoardState {
  return {
      nextIsX: true,
      squares: Array(9).fill(null),
  };
}
export default App;

BoardHook.tsx


import React from 'react';
import './BoardHook.css';
import { renderSquare } from './SquareHook';
import { BoardState } from '../tic-tac-toe/Board';

export type BoardProps = {
    state: BoardState,
    onValueChange: (key: number) => void,
}
export function renderBoard(props: BoardProps): JSX.Element {
    return (
        <div className="board-row">
                {Array.from(Array(9).keys())
                    .map(i => (renderSquare({
                        key: i,
                        value: props.state.squares[i],
                        onClick: () => props.onValueChange(i)
                    })))}
            </div>
        );
}

SquareHook.tsx


import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import React from "react";
import './SquareHook.css';
import { SquareValue } from '../tic-tac-toe/SquareValue';

export type SquareProps = {
    key: number,
    value: SquareValue,
    onClick: () => void,
};
export function renderSquare(props: SquareProps): JSX.Element {
    return (<button key={props.key} className="square"
            onClick={() => props.onClick()}>
            {props.value}
        </button>);
}

Side-effect

When the component was rendered or removed, or states were update, I could do something through "useEffect".

App.tsx


...
function App() {
  const [state, setBoardState] = useState(initialState());
  
  useEffect(() => {
    // when this component rendered, this function was called.
    console.log('load');
    document.title = (state.nextIsX)? '✕': '◯';

    // before remove this component, this function was called.
    return () => console.log('clean');
  },
  // only the "state" was updated, the functions inside "useEffect" were called.
  [state]);

...    
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div>next player: {(state.nextIsX)? '✕': '◯'}</div>
        {renderBoard({state, onValueChange: updateSquareValues })}
      </header>
    </div>
  );
}
...

Limitation

"useState" and "useEffect" had to be called from top level component. So I couldn't call them from BoardHook.tsx or SquareHook.tsx. I had been afraid the top level component would had too much responsibilities. I wanted to learn the architecture for React.

Get data from server(mock)

Next, I tried getting data from server. In this time, I just used mock.

game.service.ts


import { SquareValue } from "../tic-tac-toe/SquareValue";

export async function getSquares(): Promise<Array<SquareValue>>{
    return await new Promise(resolve =>
        setTimeout(() => resolve(Array(9).fill(null)), 1000));
}

How to use async/await ?

First, I tried accessing the function from "useState".

App.tsx (failed)


...
import { getSquares } from './tic-tac-toe-hooks/game.service';
// in index.tsx, a compile error was occurred.
async function App() {
  const [state, setBoardState] = useState(async initialState());
...
}
async function initialState(): BoardState {
  return {
      nextIsX: true,
      squares: await getSquares(),
  };
}

And I got error. Maybe because the component couldn't have async/await. "useEffect" also couldn't use them directly.

App.tsx (failed)


...
function App() {
  const [state, setBoardState] = useState(initialState());
  // compile error
  useEffect(async () => {
    setBoardState({
        nextIsX: state.nextIsX,
        squares: await getSquares()
    });
  }, []);
...

I should do this.

App.tsx


...
function App() {
  const [state, setBoardState] = useState(initialState());
  useEffect(() => {
    const get = async () => {
      setBoardState({
        nextIsX: state.nextIsX,
        squares: await getSquares()
      });
    };
    get();
  }, []);
...

How to fetch data with React Hooks? - RWieruch

コメント

このブログの人気の投稿

[PostgreSQL] Play with TypeORM 1

Intro This time, I tried accessing Database by TypeORM. Because I wanted to manage Database tables by ORM, I created a table first.  GitHub - typeorm/typeorm   TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Installation and creating a project Installation TypeORM needed "reflect-metadata" and database driver. npm install --save typeorm reflect-metadata pg typescript tsc npm install --save-dev @types/node And I also installed "ts-node" to skip compiling. npm install --save ts-node Preparing References I could generate a TypeORM project by TypeORM command. npx typeorm init --name gen-typeorm-sample --database postgres I refered Most of all settings from it. Adding files and folders First, I added tsconfig.json. npx tsc --init And I edited like below. tsconfig.json { "compilerOptions": { /* Basic Options */ "incremental": true, "target": "es5", "module": "comm...

[TypeScript] Try React 1

Intro This time I tried React. First, I referred Documents and Tutorial. React – A JavaScript library for building user interfaces GitHub - facebook/react: A declarative, efficient, and flexible JavaScript library for building user interfaces. Getting started with React - Learn web development | MDN Create a project To create a new React project, I used "Create React App". GitHub - facebook/create-react-app: Set up a modern web app by running one command. It created these files. .git node_modules public L favicon.ico L index.html L logo192.png L logo512.png L manifest.json L robots.txt src L App.css L App.test.tsx L App.tsx L index.css L index.test.tsx L index.tsx L logo.svg L react-app-env.d.ts L serviceWorker.ts L setupTests.ts .gitignore package.json package-lock.json README.md tsconfig.json Make the page work with IE11 I could view the page by "npm start" or "npm run start".   ...

[Angular 10 + NgRx + Nest.js] Create project

Intro This time, I added server-side. I choosed Nest.js because I love TypeScript and I had been interested in using TypeScript in server-side programming. Environments Angular ver.10.0.2 @ngrx/store ver.9.2.0 @ngrx/effects ver.9.2.0 @nestjs/ng-universal ver.2.0.1 Couldn't add @ngrx/store into the Angular 10 project First, I created an Angular project and tried adding @ngrx/store into it. And I got an error. Installing packages for tooling via npm. Installed packages for tooling via npm. The package that you are trying to add does not support schematics. You can try using a different version of the package or contact the package author to add ng-add support. According to the issue below, I should add "@latest". npx ng add @ngrx/store@latest Because if I didn't add it, the @ngrx/store version was too low.    cannot use ng add to install ngrx store · Issue #2604 · ngrx/platform · GitHub Though I didn't know I should add "@latest" into ...