GithubHelp home page GithubHelp logo

Comments (28)

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

型定義のオプション化

// titleおよびcolorはstringもしくはundefinedとなる
type ButtonProps = {
  title?: string
  color?: string
}

?をつけるとそのプロパティは省略可能になる

全部に?を付けたい場合はPartial<>を使った方が便利

type ButtonProps = Partial<{
  title: string
  color: string
}>

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

関数コンポーネントの型定義

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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
};

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

ReactNodeについて

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined

用途

  • Reactの型定義で、childrenに渡せる型はReactNodeだけに決まっている(要するにchildrenの型を指定する時は、ReactNodeで書いた方が良い)

JSX.Elementとの違い

  • JSX.ElementReactElement である( ReactElement を継承している )
    • interface Element extends React.ReactElement<any, any> { }という定義
  • 特に理由がなければ ReactNode で困らないし、後々 string なり null なり渡したい時に便利
  • React環境下なら JSX.Element より React.ReactElement を使っていった方が齟齬がない

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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()
  }, []);

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

クリーンアップ関数について

  • クリーンアップ関数:前回の副作用の効果を消去する関数
  • クリーンアップ関数を設定しないとメモリリークなどが発生する可能性がある
    • 例えば前回のレンダリング時に設定したタイマーがずっと生きていて多重にタイマーが動いているかもしれない

const Foo = () => {
  useEffect(() => {
    // ここがコールバック関数
    console.log("Fooがマウントされました!");
    // ↓これがクリーンアップ関数
    return () => {
      console.log("Fooがアンマウントされる!");
    };
  }, []);
  return <p>I am foo</p>;
};

useEffectにおけるクリーンアップ関数の実行タイミング

  • コンポーネントが再レンダリングされる時と、アンマウントされる時でタイミングは異なる

再レンダリング時

  1. 新しいレンダリング
  2. 新しいレンダリングがDOMに反映
  3. 更新されたDOMが画面に反映される
  4. クリーンアップ関数の実行
  5. 新しいコールバック関数の実行

アンマウント時

  1. 新しいレンダリング
  2. 新しいレンダリングがDOMに反映
  3. 更新されたDOMが画面に反映される
  4. クリーンアップ関数の実行
  • 上はReact17での場合(React16では異なる)
  • つまりクリーンアップ関数が実行される時には、古いDOMがないので、クリーンアップ関数の中に古いDOMに対する操作を入れてはいけない

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

Reactのstate更新タイミング

  • Reactではstateはすぐに更新されない
    • 不必要な再レンダーを防ぐためらしい
  • setStateで値が更新されるのは関数が呼び出された後

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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だとLinkNavLinkが使えるので基本こっちを使う

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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>
);

使い方としては、

  1. createContextでコンテクストを作成する
  2. MyContext.Providerでpropsを渡したいコンポーネントを包む
  3. useContextでpropsを取り出して使う
    みたいな感じ

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

イベントハンドラ

イベントハンドラの渡し方に注意

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

Reactはいつレンダリングを行うか?

基本的には

  1. stateが更新されたとき
  2. propsが更新されたとき
  3. 親コンポーネントが更新されたとき(propsが変化してなくても)

にレンダリングが行われる。
しかし、3番目により、意識しないと無駄なレンダリングにつながってしまう。
その結果、UIの描写に時間がかかったりしてしまう。

レンダリングをスキップするためにはmemouseCallbackuseMemoを使ってメモ化を行う。
(だが、実際にはmemoなどを使うよりはdivタグを減らすなどのほうがパフォーマンスは上がるみたい)
(メモ化:同じ結果を返す処理について、初回のみ処理を実行記録しておき、値が必要となった2回目以降は、前回の処理結果を計算することなく呼び出し値を得られるようにすること)

memo

React.memoはコンポーネントをラップする。propsが同じだったら親コンポーネントが更新されても再描画せずに、以前の結果を描画する。
stateが更新されたときは新しくレンダーする。

useCallback

コンポーネントを再描写するとそのコンポーネントの中で定義されている関数も新たに作り直される。そしてその関数をpropsとして子コンポーネントに渡すと、関数自体は変わって無くてもpropsが変更されたことになるので、子コンポーネントが再描画されてしまい、不必要な再描画を招く。
useCallbackは関数自体をメモ化する。依存する引数が変化しなければ、以前と同じ関数を返す。

useMemo

useCallbackは関数自体をメモ化するが、useMemoは関数の結果をメモ化する。
「計算負荷は高いが、何回やっても結果は変わらない」みたいなときに使う。
(関係のない部分が変更されてコンポーネントが再描写されるたびにコストの高い計算が行われることを防ぐ)

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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 の型定義ファイルの探索アルゴリズム

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

TypeScriptのアクセス制御

TypeScriptではclass内のオブジェクト(メンバーや関数など)にprivateprotectedpublicの修飾子を付けてアクセス制御ができる

  • 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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

クラスの型

TypeScriptでは、クラスを定義すると同時に同名の型も定義される。

class Foo {
  method(): void {
    console.log('Hello, world!');
  }
}

const obj: Foo = new Foo();

クラスFooが定義されたことで型Fooも同時に定義される
最後のobj: FooFooは型のFoonew Foo()FooはクラスFooの実体)

ちなみにここの型Fooは以下と同じ

interface MyFoo {
  method: ()=> void;
}

const obj: MyFoo = new Foo(); //エラーは出ない

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

TypeScriptとJSON

JSONをparseした結果はany型として扱われてしまう。
そのため予期しない型のデータが取得された場合、予期しないところでエラーが発生する。
型推論をさせてしまうのもダメ。
回避するためにはデータの取得段階でvalidationを掛ける必要がある。

validationに使えるのは**@mojotech/json-type-validation**というライブラリ

参照

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

Reactのマウント・レンダリング

この図が分かりやすい
スクリーンショット 2021-12-11 15 02 34

  • レンダリング:DOMを作る処理、propsやstateの更新を読み込む
  • マウント:最初にDOMを作る処理、constructorの値を読み込む、レンダリングもマウントの一部

なので、useStateの初期値はマウント時にしか読み込まれない(constructorのstateなので)
コンポーネントがレンダリングされるたびにstateが初期値に戻ったりしない
初期値を頻繁に使いたいならpropsとして扱うのがベター

コンポーネント内の関数はレンダリングの度に実行されるので注意
副作用のあるような関数はレンダリング時ではなくマウント時に実行させるのが良い
マウント時のみ実行させたいならuseEffectを使う

from self-study.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

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.

Yuya-Furusawa avatar Yuya-Furusawa commented on July 28, 2024

hydrate

ReactでSSRをする際に使う。すでに存在するmarkupにevent listenerなどをアタッチする。
(hydrate = 水を与える、event listenerの無い干からびたHTMLにevent listenerという水を与えるイメージ)

レンダーされる内容がサーバーとクライアントで一致していなくてはならない。
なのでReactDOMServerなどを用いてマークアップを用意する必要がある

参照

from self-study.

Related Issues (11)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.