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
コメント
コメントを投稿