Comments (28)
型定義のオプション化
// titleおよびcolorはstringもしくはundefinedとなる
type ButtonProps = {
title?: string
color?: string
}
?
をつけるとそのプロパティは省略可能になる
全部に?
を付けたい場合はPartial<>
を使った方が便利
type ButtonProps = Partial<{
title: string
color: string
}>
from self-study.
関数コンポーネントの型定義
const Summary: React.FC<Props, State> = (props) => {
hogehoge;
};
React.FC<>
について、第一引数にpropsの型、第二引数にstateの型を指定する
指定しない場合やstateが無い場合は、<Props, {}>
、<Props>
、<{}, State>
という形にする
useStateの型定義
const [count, setCount] = useState<Type>(0);
setCount()
にType
以外の型を入れようとするとエラーになる
booleanとか使う時に便利
const [isHoshimiya, setIsHoshimiya] = useState<boolean>(true);
だが基本的にTypeScriptでは型推論してくれるのであんまり型指定しなくても大丈夫
// countの型はnumberになる
// setCount()にnumber以外を入れるとエラーになる
const [count, setCount] = useState(0);
参照
from self-study.
Typeか?Interfaceか?
- typeとinterfaceの大まかな機能はほとんど同じ
- interfaceはdeclaration mergingができる(そんな使わないけど)
- typeはunion型とか作れる
- interfaceはコンポーネントとかの型定義に用いることが多い
- typeは型合成などで独自の型を定義する時に用いることが多い
- しかしそれはプロジェクトの方針に寄るという感じかも
例
type Foo = number;
type Hoge = string;
type FooHoge = Foo | Hoge; //独自の型
//関数のPropsの型を定義するときはinterface
interface Props {
contents: FooHoge;
};
const Card: React.FC<Props> = (contents) => {
hogehoge
};
参照
- TypeScript の Interface と Type Alias の違い
- TypeScriptのInterfaceとTypeの比較
- TypeScript で type と interface どっち使うのか問題
from self-study.
propsの分割代入
propsを渡すときにコード量を減らせる
(props)
ではなく({ hogehoge })
と書けば記述量を減らせる
修正前
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
}
const Headline = (props) => {
return <h1>{props.value}</h1>;
}
修正後
const App = () => {
const greeting = 'Hello Function Component!';
return <Headline value={greeting} />;
}
const Headline = ({ value }) => {
return <h1>{value}</h1>;
}
おまけ:スプレッド構文も使える
こんな風に、propsが2つ以上ある時、
const Button = ({ children, onClick }) => {
return <button onClick={onClick}>{children}</button>
}
スプレッド構文を使ってpropsの記述を減らせる
const Button = (props) => {
return <button {...props} />
}
ただしこの場合、可読性が下がるのであまりやるべきでは無い!!
参照
from self-study.
ReactNodeについて
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined
用途
- Reactの型定義で、childrenに渡せる型は
ReactNode
だけに決まっている(要するにchildrenの型を指定する時は、ReactNode
で書いた方が良い)
JSX.Element
との違い
JSX.Element
はReactElement
である(ReactElement
を継承している )interface Element extends React.ReactElement<any, any> { }
という定義
- 特に理由がなければ
ReactNode
で困らないし、後々string
なりnull
なり渡したい時に便利 - React環境下なら
JSX.Element
よりReact.ReactElement
を使っていった方が齟齬がない
参照
- https://github.com/eagna-io/predictiongeeks/pull/294#discussion_r567202165
- Reactのコンポーネント周りの用語を整理する
- 雰囲気で使わない @types/react
- TypeScript: ReactNode型とReactElement型とReactChild型
from self-study.
useEffectについて
useEffect
に渡された関数はレンダーの結果が画面に反映された後に動作する- 関数の実行タイミングをReactのレンダリング後まで遅らせるhook
- クラスコンポーネントでいうところの下の関数をまとめたもの
componentDidMount
- コンポーネントがDOMとして描写された(マウントされた)後に関数を実行する
componentDidUpdate
- DOMが更新される度に関数を実行する
componentWillUnmount
- DOMが削除された後に関数を実行する
用例
// useEffectの場合
useEffect(() => {
document.title =`${count}回クリックされました`
})
// クラスコンポーネントの場合
componentDidMount(){
document.title =`${this.state.count}回クリックされました`
}
componentDidUpdate(){
document.title =`${this.state.count}回クリックされました`
}
第2引数
第2引数に配列を渡すと、「これの値が変わった時だけコンポーネントを再レンダーする!」みたいなことができる
// useEffectを使った場合
useEffect(() => {
elm.addEventListener('click', () => {})
return () => {
elm.removeEventListener('click', () => {})
}
}, [])
// countに変化があった時だけ関数を実行
useEffect(() => {
document.title =`${count}回クリックされました`
},[count])
第2引数に空の配列を渡すと、初回のレンダー時のみ関数を実行する(= componentDidMount
と同じになる)
// 初回だけ関数を実行
useEffect(() => {
document.title =`${count}回クリックされました`
},[])
//これと同じ
componentDidMount(){
document.title =`${this.state.count}回クリックされました`
}
クリーンアップについて
クリーンアップ関数をuseEfffect
内でreturnすると2度目以降のレンダリング時に前回の副作用を消してしまうことができる。
イベントリスナの削除やタイマーのキャンセルなどを行うことができる。
useEffect(() => {
elm.addEventListener('click', () => {})
// returned function will be called on component unmount
return () => {
elm.removeEventListener('click', () => {})
}
}, [])
useEffectで非同期処理をするときの注意
useEffectの第一引数として非同期関数を設定できない
というのも、第一引数として設定する関数の戻り値はundefinedもしくはcleanup関数でなくてはならない、ため
//これはエラー
//戻り値がPromiseインスタンスになっている
useEffect(async () => {
const response = await fetch("https://www.googleapis.com/books/v1/volumes?q=AWS");
const data = await response.json();
console.log(data);
},[]);
正しくは以下の通り
//これはOK
useEffect(() => {
const data = async() => {
const response = await fetch("https://www.googleapis.com/books/v1/volumes?q=AWS");
const data = await response.json();
alert(data.totalItems);
}
data()
}, []);
参照
- React hooksを基礎から理解する (useEffect編)
- state とライフサイクル(React公式)
- useEffectでcomponentDidMountを代用する
- クリーンアップを有する副作用(React公式)
- useEffectに非同期関数を設定する方法
- 【async/await】useEffect内で非同期処理を行う方法を解説
- A Visual Guide to useEffect
from self-study.
Boolean Props
propsにboolean型を渡すことがもちろんできる
true
を渡す時
render() {
return (
<Movie released={true} />
)
}
簡略化可能
render() {
return (
<Movie released /> //何を指定しなくてもtrueになる
)
}
false
を渡す時
render() {
return (
<Movie released={false} />
)
}
何も渡さないとundefined
が渡される
render() {
return (
<Movie /> // propsを指定しなかったらundefinedを渡してるのと同じ、真偽値判定はfalseになる
)
}
- ただし、typescriptを併用する場合は型指定に注意
- optionalにしてboolean指定
- undefinedを許容するならoptionalにした方が良い
参照
from self-study.
export/import について
exportの仕方には、"named export"と"default export"の2種類がある。
//named export
export const sqrt = Math.sqrt;
import { sqrt } from "./hoge"; // { }を使う
//default export
export default const sqrt = Math.sqrt;
import sqrt from "./hoge"; // { }はいらない
default exportは1つのファイルにつき1つしか指定できない。
さらに、named exportはimportする時に、対応するオブジェクトと同じ名前を使用しなくてはいけない。
しかし、default exportはimport側で任意の名前で呼び出すことができる(ただしこれにより後々リファクタリングがめんどくさくなる可能性も)。
// test.js
let k; export default k = 12;
// 他のファイル
import m from './test'; // k がdefault exportなのでimportする k の代わりに m を使用することができる
console.log(m);
参照
from self-study.
クリーンアップ関数について
- クリーンアップ関数:前回の副作用の効果を消去する関数
- クリーンアップ関数を設定しないとメモリリークなどが発生する可能性がある
- 例えば前回のレンダリング時に設定したタイマーがずっと生きていて多重にタイマーが動いているかもしれない
例
const Foo = () => {
useEffect(() => {
// ここがコールバック関数
console.log("Fooがマウントされました!");
// ↓これがクリーンアップ関数
return () => {
console.log("Fooがアンマウントされる!");
};
}, []);
return <p>I am foo</p>;
};
useEffect
におけるクリーンアップ関数の実行タイミング
- コンポーネントが再レンダリングされる時と、アンマウントされる時でタイミングは異なる
再レンダリング時
- 新しいレンダリング
- 新しいレンダリングがDOMに反映
- 更新されたDOMが画面に反映される
- クリーンアップ関数の実行
- 新しいコールバック関数の実行
アンマウント時
- 新しいレンダリング
- 新しいレンダリングがDOMに反映
- 更新されたDOMが画面に反映される
- クリーンアップ関数の実行
- 上はReact17での場合(React16では異なる)
- つまりクリーンアップ関数が実行される時には、古いDOMがないので、クリーンアップ関数の中に古いDOMに対する操作を入れてはいけない
参照
from self-study.
Reactでのselectフォーム
基本的な構文(Functional Componentの場合)
const FlavorForm = () => {
const [flavor, setFlavor] = useState('coconut');
handleSubmit(event) {
alert('Your favorite flavor is: ' + flavor);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>
Pick your favorite flavor:
<select value={flavor} onChange={(e) => setFlavor(e.target.value)}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
- 基本的にstateで管理し、onChangeでstateを変更する
selected
属性の代わりにReactではselectタグのvalue属性を使用する
参照
from self-study.
Reactのstate更新タイミング
- Reactではstateはすぐに更新されない
- 不必要な再レンダーを防ぐためらしい
- setStateで値が更新されるのは関数が呼び出された後
参照
from self-study.
React Routerについて
- React RouterはReactでルーティングを実装するためのパッケージ
- ルーティングとは、ユーザーからの入力に応じて表示させるページを出し分ける処理
- ルーティングによりURLで画面を指定する
- SPA(Single Page Application)の画面状態とURLとを紐づけるルーティングを行うことで、history API を操作できるようにする
- ブラウザバックとかできるようになる
使い方
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom';
import { Home, About, Dashboard } from './component';
const App = () => {
return (
<BrowserRouter>
<div>{document.title}</div>
<Switch>
<Route exact path='/' component={Home} />
<Route exact path='/about' component={About} />
<Route exact path='/dashboard' component><Dashboard /></Route>
</Switch>
<Link to='/'>Back To Home</Link>
</BrowserRouter>
)
}
BrowserRouter
の中にRoute
を入れるRoute
の中でpathとそれに対応して表示するコンポーネントを指定するexact
の指定が重要- URLが厳密に一致するときだけレンダリングする
- 特に
path='/'
にexact
を指定しないと/about
でも/dashboard
でもHome
が表示されてしまう
react-routerとreact-router-domの違い
- どちらもルーティングを行うという点では変わらない
- react-router-domだと
Link
やNavLink
が使えるので基本こっちを使う
参照
- React入門 ~React Router編~
- React.jsでルーティングを実装するためのreact-routerの紹介
- 【React】ルーティング設定方法
- react-router-dom
- react-routerとreact-router-domの違い
from self-study.
React Contextについて
Contextを使うと、propsのバケツリレーを防ぐことができる
// まずはコンテクストを作成
// 引数はdefault value
const ResourceContext = React.createContext("");
export const RootComponent = () => {
const resource = getResource(); // 何らかのデータを取ってくる
return (
// Providerコンポーネントで包むことによって、Provider配下のコンテキストを決定する
// このvalueが今までバケツリレーしていたprops
<ResourceContext.Provider value={resource.name}>
<NavigationComponent />
<BodyComponent />
</ResourceContext.Provider>
);
};
export const NavigationComponent = (props) => {
// useContextのhooksを使う
// 値はResourceContext.Providerのvalueで決定される
const resourceName = React.useContext(ResourceContext);
return (
<header>
<TitleComponent title={resourceName} />
<NannkanoButtonComponent />
<NannkanoMenuComponent />
</header>
);
};
export const TitleComponent = (props) => (
<div>{props.title}</div>
);
export const BodyComponent = (props) => {
// ココも!
const resourceName = React.useContext(ResourceContext);
return (
<main>
<ResourceTitleComponent name={resourceName} />
...
</main>
);
};
export const ResourceTitleComponent = (props) => (
<article>{props.name}</article>
);
使い方としては、
createContext
でコンテクストを作成するMyContext.Provider
でpropsを渡したいコンポーネントを包むuseContext
でpropsを取り出して使う
みたいな感じ
参照
from self-study.
useReducerについて
import React, { useReducer } from 'react';
function Counter() {
// useReducerの第1引数はstateとactionを引数に持つ関数、第2引数はstateの初期値
// sumはstate
const [sum, dispatch] = useReducer((state, action) => {
return state + action;
}, 0);
return (
<>
{sum}
// dispatchはuseReducerに渡した関数のこと
// dispatchにわたす引数はその関数でいうaction
<button onClick={() => dispatch(1)}>
Add 1
</button>
</>
);
}
typeとかを使ってReduxっぽく応用することが多いっぽい?
import React, {useReducer} from 'react ';
const [state, dispatch] = useReducer(authReducer, initialState);
function authReducer(state, action){
// typeによって処理を変える
switch (action.type) {
case 'LOGIN':
return {
...state,
user: action.payload
};
case 'LOGOUT':
return {
...state,
user: null
};
default:
return state;
}
}
function login(userData){
// typeは'LOGIN'としてdispatch(=authReducer)関数を呼び出す
dispatch({
type: 'LOGIN',
payload: userData
});
}
function logout(){
// typeは'LOGIN'としてdispatch(=authReducer)関数を呼び出す
dispatch({ type: 'LOGOUT' });
}
参照
from self-study.
React Routerを用いてURLパラメターを取得する
まずは動的なルートを定義する
import { BrowserRouter as Router, Route } from 'react-router-dom';
<Router>
<Route path='/posts/:postId' component={SinglePost} />
</Router>
このとき、以下のように取得できる
const SinglePost = (props) => {
const postId = props.match.params.postId;
}
ちなみに型定義する場合は、
import { RouteComponentProps } from 'react-router-dom';
type PostProps = RouteComponentProps<{
// パラメータの型を指定する
postId: string;
}>;
const SinglePost: FC<PostProps> = (props) => {
const postId = props.match.params.postId;
}
参照
from self-study.
useRefについて
そもそもRef
はあまり使うべきでは無いらしい、以下のときに使う(公式より)
- フォーカス、テキストの選択およびメディアの再生の管理
- アニメーションの発火
- サードパーティの DOM ライブラリとの統合
useRef
を用いると要素への参照を行うことができる
//100は初期値
const number = useRef(100);
//current属性で値を取得
console.log(number.current); // 100
DOMの参照で使われることが多い模様
const inputElement = useRef(null)
//例: inputElement.currentで <input type="text" /> を参照
<input ref={inputElement} type="text" />
console.log(inputElement.current); // <input type="text" />
useRef
(というかRef
)を用いるとコンポーネントの再描画はせずに、内部の値だけ更新する、みたいなことができる
参照
from self-study.
React Portalについて
- React Portalを使うとレンダリングを行うDOMを選ぶことができる
- 別のDOMにレンダリングすると適用するCSSを変えることなどができる
- Modalつくるときとかに有用
public/index.html
<body>
(...省略)
<div id="modal"></div>
<div id="root"></div>
</body>
src/ModalPortal.js
import ReactDOM from 'react-dom';
const ModalPortal = ({ children }) => {
const el = document.getElementById('modal');
// id="modal"に対してPortalを作成する
return ReactDOM.createPortal(children, el);
};
export default ModalPortal;
src/App.js
import "./App.css";
import Modal from "./Modal";
import ModalPortal from "./ModalPortal";
export default function App() {
return (
<div className="App">
<h1>Hello World</h1>
// Portalで囲った部分(Modal)が別のDOMにレンダリングされる
<ModalPortal>
<Modal />
</ModalPortal>
</div>
);
}
参照
from self-study.
propsの型定義
propsの分割代入を行うときにどうやって型定義を行うか
例
// 型を定義
type AppProps = {
message: string;
};
// 分割代入をしない場合
const App = (props: AppProps) => <div>{message}</div>;
// 定義した型を使って型定義
const App = ({ message }: AppProps) => <div>{message}</div>;
// 返り値の型を指定する場合
const App = ({ message }: AppProps): JSX.Element => <div>{message}</div>;
// 定義した型を使わない場合、ただし可読性は下がる
const App = ({ message }: { message: string }) => <div>{message}</div>;
参照
from self-study.
イベントハンドラ
イベントハンドラの渡し方に注意
function showMessage(){
console.log('message);
}
// ボタンクリック時に関数が実行される
<button onClick={showMessage}>ボタン</button>
// 無名関数を使ってもOK
<button onClick={() => showMessage()}>ボタン</button>
// 引数がある場合
// 関数の方に引数を入れる
<button onClick={() => showMessage(mes)}>ボタン</button>
以下のパターンはNG
JSXが評価されるタイミングで実行されてします
<button onClick={showMessage()}>ボタン</button>
// 引数あるときも注意
<button onClick={showMessage(mes)}>ボタン</button>
参照
from self-study.
string
型とString
型について
TypeScriptを使うときにstring
型とString
型を混在して使っていたので整理
string
型
- プリミティブ型
const str1 = "string";
console.log(typeof str1); // string
String
型
- オブジェクト型
const str2 = String("string");
console.log(typeof str2); // String
どっちを使えば良いか?
- これらは厳密に異なる
- 基本的には
string
を用いる- 公式も言ってる
参照
from self-study.
Reactはいつレンダリングを行うか?
基本的には
- stateが更新されたとき
- propsが更新されたとき
- 親コンポーネントが更新されたとき(propsが変化してなくても)
にレンダリングが行われる。
しかし、3番目により、意識しないと無駄なレンダリングにつながってしまう。
その結果、UIの描写に時間がかかったりしてしまう。
レンダリングをスキップするためにはmemo
やuseCallback
、useMemo
を使ってメモ化を行う。
(だが、実際にはmemoなどを使うよりはdiv
タグを減らすなどのほうがパフォーマンスは上がるみたい)
(メモ化:同じ結果を返す処理について、初回のみ処理を実行記録しておき、値が必要となった2回目以降は、前回の処理結果を計算することなく呼び出し値を得られるようにすること)
memo
React.memo
はコンポーネントをラップする。propsが同じだったら親コンポーネントが更新されても再描画せずに、以前の結果を描画する。
stateが更新されたときは新しくレンダーする。
useCallback
コンポーネントを再描写するとそのコンポーネントの中で定義されている関数も新たに作り直される。そしてその関数をpropsとして子コンポーネントに渡すと、関数自体は変わって無くてもpropsが変更されたことになるので、子コンポーネントが再描画されてしまい、不必要な再描画を招く。
useCallback
は関数自体をメモ化する。依存する引数が変化しなければ、以前と同じ関数を返す。
useMemo
useCallback
は関数自体をメモ化するが、useMemo
は関数の結果をメモ化する。
「計算負荷は高いが、何回やっても結果は変わらない」みたいなときに使う。
(関係のない部分が変更されてコンポーネントが再描写されるたびにコストの高い計算が行われることを防ぐ)
参照
- 【React】再レンダリングの仕組みと最適化
- Reactの再描画について調べた
- Reactのレンダリングに関する完全ガイド
- お前らのReactは遅い
- React.memo(React公式)
- useCallback(React公式)
- useMemo(React公式)
- React hooksを基礎から理解する (useCallback編+ React.memo)
from self-study.
TypeScriptで型定義ファイルが無い時の対処法
例えば、あるモジュールをimportしたときに
import hoge from 'fugafuga';
こんなエラーが出る時がある
Could not find a declaration file for module 'fugafuga'.
Try npm install @types/fugafuga if it exists or add a new declaration (.d.ts) file containing declare module 'fugafuga';
これはモジュールの型定義ファイルが無くTypeScriptに対応できていないことによる
メジャーなパッケージなら@types/fugafuga
という型定義ファイルがあるのでそれをインストールすればOK
@types
がなければ自分で型定義ファイルを自作する必要がある
型定義ファイルの作成
.d.ts
ファイルを作成する(.ts
ファイルでもOK)
ファイルの拡張子が.d.ts
の場合、各ルートレベルの定義にはdeclare
というキーワードを前に付ける必要がある
// fugafuga.d.ts
declare module 'fugafuga';
こうすればエラーは解消される
が、moduleをimportすると型は暗黙的にany
になる
ちゃんと型付けを行う時はこんな感じ
// fugafuga.d.ts
declare module 'fugafuga' {
export function getRandomNumber(): number
}
import { getRandomNumber } from 'fugafuga';
const x = getRandomNumber(); // x is inferred as number
自分が使うオブジェクトに対してだけ型付けを行えば十分
型定義ファイルの配置・名前について
declare module
をした(これをアンビエントモジュール宣言という)モジュールはどこに配置しても大丈夫
アンビエントモジュール宣言はプロジェクト全体に適用される
しかしあくまでもTSのコンパイルが通る必要があるため、tsconfig.json
で設定したコンパイルの箇所には配置する必要あり
型定義ファイルの名前は何でもよい(中身が重要)が、実務的には宣言するモジュールごとにファイルを分け、src/@types/
以下に配置することが多い
面倒な場合はglobal.d.ts
みたいにすることもある
※注意1
トップレベルにimport
してしまうとアンビエントモジュール宣言にならずグローバルにならない
他のファイルからexportしたものを宣言に使うときはdeclare
ブロックの中でimport
する必要あり
参照:Import class in definition file (*d.ts) - stackoverflow
※注意2
独自に.d.ts
ファイルや.ts
ファイルを作りアンビエントモジュール宣言を行わなくても型定義をすることはできる
しかしdeclare module
が一番優先されるので、基本的にはこれを使うのが良さそう
アンビエントモジュール宣言を用いない場合は、ファイルの配置箇所・ファイル名には気をつける必要あり
参照:TypeScript の型定義ファイルの探索アルゴリズム
参照
- 型定義ファイル(TypeScript Deep Dive 日本語版)
- Could not find a declaration file for module 'module-name'. '/path/to/module-name.js' implicitly has an 'any' type (StackOverFlow)
- TypeScript の型定義ファイルと仲良くなろう
- TypeScriptの型: 既存の JavaScript ライブラリに型情報を追加する(.d.ts ファイル)
- TypeScript で型定義ファイル( d.ts )がないときの対処法
- Typescript ambient module declarations
- Ambient Modules - TypeScript
from self-study.
TypeScriptのアクセス制御
TypeScriptではclass内のオブジェクト(メンバーや関数など)にprivate
、protected
、public
の修飾子を付けてアクセス制御ができる
private
:class以外では参照することができない(子クラス内やインスタンス化したときに参照できない)protected
:子クラス内では参照できるがインスタンス化したら参照できないpublic
:いつでもどこからでも参照できる(何もしなくてもそうなるので、コメント的な意味合いになる)
class SmallDog {
private secretPlace: string; //アクセス制御
dig(): string {
return this.secretPlace;
}
bury(treasure: string) {
this.secretPlace = treasure;
}
}
const miniatureDachshund = new SmallDog();
miniatureDachshund.bury("骨");
// インスタンスからはアクセスできない
// error TS2341: Property 'secretPlace' is private and only accessible within class 'SmallDog'.
miniatureDachshund.secretPlace;
console.log(miniatureDachshund.dig()); // 骨
ちなみにコンストラクタの引数としてプロパティを宣言できる
class SmallDog {
constructor(private secretPlace: string) {
}
...
}
参照
from self-study.
クラスの型
TypeScriptでは、クラスを定義すると同時に同名の型も定義される。
class Foo {
method(): void {
console.log('Hello, world!');
}
}
const obj: Foo = new Foo();
クラスFoo
が定義されたことで型Foo
も同時に定義される
最後のobj: Foo
のFoo
は型のFoo
(new Foo()
のFoo
はクラスFoo
の実体)
ちなみにここの型Foo
は以下と同じ
interface MyFoo {
method: ()=> void;
}
const obj: MyFoo = new Foo(); //エラーは出ない
参照
from self-study.
TypeScriptとJSON
JSONをparseした結果はany
型として扱われてしまう。
そのため予期しない型のデータが取得された場合、予期しないところでエラーが発生する。
型推論をさせてしまうのもダメ。
回避するためにはデータの取得段階でvalidationを掛ける必要がある。
validationに使えるのは**@mojotech/json-type-validation**というライブラリ
参照
from self-study.
Reactのマウント・レンダリング
- レンダリング:DOMを作る処理、propsやstateの更新を読み込む
- マウント:最初にDOMを作る処理、constructorの値を読み込む、レンダリングもマウントの一部
なので、useState
の初期値はマウント時にしか読み込まれない(constructorのstateなので)
コンポーネントがレンダリングされるたびにstateが初期値に戻ったりしない
初期値を頻繁に使いたいならpropsとして扱うのがベター
コンポーネント内の関数はレンダリングの度に実行されるので注意
副作用のあるような関数はレンダリング時ではなくマウント時に実行させるのが良い
マウント時のみ実行させたいならuseEffect
を使う
from self-study.
TypeScriptで関数の型付け
ちゃんと型付けする場合はこんな感じ
function lengthOrDefault(str: string | null, defaultLength: number): number {
return str != null ? str.length : defaultLength;
}
戻り値の型推論
戻り値の型付けを省略した場合はreturn
されている式から型推論される
// foo は (num: number) => "hoge" | "fuga" 型
function foo(num: number) {
if (num >= 0) {
return "hoge";
} else {
return "fuga";
}
}
return
文が無いときはvoid
型が推論される。
return
文はあるけどreturn
せずに終了する場合があるときはundefined
になる。
// fooの返り値は "hoge" | undefined 型
function foo(num: number) {
if (num >= 0) {
return "hoge";
}
}
undefined
にするのではなくエラーにしたい場合はtsconfig.js
の設定を変更すればOK
引数の型推論
「変数の型は宣言時に決まる」ため、関数が使われる際に推論は行われない。
型注釈がない場合、any型として推論される。
// 引数はany型として扱われてしまう。
// 設定によってはimplicit anyということでエラー
function foo(num) {
if (num >= 0) {
return "hoge";
}
}
なので、基本的には引数は型注釈を与える必要がある。
ただし、contextual typeがあるときは引数に型注釈を与える必要はない。
type Func = (arg: number) => number;
const double: Func = function(num) {
// 引数 num の型は number 型と推論されている
return num * 2;
};
参照
from self-study.
hydrate
ReactでSSRをする際に使う。すでに存在するmarkupにevent listenerなどをアタッチする。
(hydrate = 水を与える、event listenerの無い干からびたHTMLにevent listenerという水を与えるイメージ)
レンダーされる内容がサーバーとクライアントで一致していなくてはならない。
なのでReactDOMServer
などを用いてマークアップを用意する必要がある
参照
- React -
hydrate()
- Understanding Hydration in React applications(SSR)
- Difference Between Hydration and Rendering in React
from self-study.
Related Issues (11)
- 開発の進め方に関する学習 HOT 3
- JavaScriptに関して調べたことのまとめ HOT 16
- PATHのお話 HOT 2
- いろいろな概念・用語 HOT 4
- Dockerについて HOT 5
- CSSとか、CSS in JSとか HOT 14
- Node.jsについて HOT 3
- Terraformについて HOT 4
- AWSとか HOT 3
- GitHub Actionsについて
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from self-study.