React JSX

# 概要

TypeScript Deep DiveのReact JSXをやってみる。

https://typescript-jp.gitbook.io/deep-dive/tsx/react
https://basarat.gitbooks.io/typescript/docs/jsx/react.html

# Function Components(関数コンポーネント)

`React.FunctionComponent`を使用して関数コンポーネントを定義する。
以降は、`<script type="text/babel">`～`</script>`を変更していくことにする。

```html:index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />

    <title>Hello React!</title>

    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
</head>

<body>
    <div id="root"></div>
</body>

</html>

<script type="text/babel">

    type Props = {
      foo: string;
    }
    
    const MyComponent: React.FunctionComponent<Props> = (props) => {
        return <span>{props.foo}</span>
    }

    ReactDOM.render(<MyComponent foo="bar" />, document.getElementById('root'));

</script>
```

# Class Components(クラスコンポーネント)

Componentクラスを継承して独自クラスを作成する。

```typescript:index.d.tsからComponentクラス抜粋
// Base component for plain JS classes
// tslint:disable-next-line:no-empty-interface
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> { }
class Component<P, S> {
    // tslint won't let me format the sample code in a way that vscode likes it :(
    /**
     * If set, `this.context` will be set at runtime to the current value of the given Context.
     *
     * Usage:
     *
     * ```ts
     * type MyContext = number
     * const Ctx = React.createContext<MyContext>(0)
     *
     * class Foo extends React.Component {
     *   static contextType = Ctx
     *   context!: React.ContextType<typeof Ctx>
     *   render () {
     *     return <>My context's value: {this.context}</>;
     *   }
     * }
     * ```
     *
     * @see https://reactjs.org/docs/context.html#classcontexttype
     */
    static contextType?: Context<any>;

    /**
     * If using the new style context, re-declare this in your class to be the
     * `React.ContextType` of your `static contextType`.
     *
     * ```ts
     * static contextType = MyContext
     * context!: React.ContextType<typeof MyContext>
     * ```
     *
     * @deprecated if used without a type annotation, or without static contextType
     * @see https://reactjs.org/docs/legacy-context.html
     */
    // TODO (TypeScript 3.0): unknown
    context: any;

    constructor(props: Readonly<P>);
    /**
     * @deprecated
     * @see https://reactjs.org/docs/legacy-context.html
     */
    constructor(props: P, context?: any);

    // We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
    // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
    // Also, the ` | S` allows intellisense to not be dumbisense
    setState<K extends keyof S>(
        state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
        callback?: () => void
    ): void;

    forceUpdate(callBack?: () => void): void;
    render(): ReactNode;

    // React.Props<T> is now deprecated, which means that the `children`
    // property is not available on `P` by default, even though you can
    // always pass children as variadic arguments to `createElement`.
    // In the future, if we can define its call signature conditionally
    // on the existence of `children` in `P`, then we should remove this.
    readonly props: Readonly<{ children?: ReactNode }> & Readonly<P>;
    state: Readonly<S>;
    /**
     * @deprecated
     * https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
     */
    refs: {
        [key: string]: ReactInstance
    };
}
```

独自クラスの実装例。

```html:index.html
<!-- 省略 -->
<script type="text/babel">

    type Props = {
      foo: string;
    }
    
    class MyComponent extends React.Component<props, {}> {
        render() {
            return <span>{this.props.foo}</span>
        }
    }

    ReactDOM.render(<MyComponent foo="bar" />, document.getElementById('root'));

</script>
```

# React JSX Tip: Interface for renderable

`React.ReactNode`型を使用すると、レンダリング可能なインターフェイスとして使える。

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    type Props = {
        header: React.ReactNode;
        body: React.ReactNode;
    }

    class MyComponent extends React.Component<Props, {}> {
        render() {
            return <div>
                {this.props.header}
                {this.props.body}
            </div>;
        }
    }

    ReactDOM.render(<MyComponent header={<h1>Header</h1>} body={<i>body</i>} />, document.getElementById('root'));

</script>
```


# React JSX Tip: Accept an instance of a Component

`React.ReactElement<T>` コンポーネントのインスタンスにアノテーションを付けられる。`const foo = <MyAwesomeComponent />; ` で良い気もするけど、配列とかだと、ジェネリック型が効いてくるのかな？

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    class MyAwesomeComponent extends React.Component<Props, {}> {
        render() {
            return <div>Hello</div>;
        }
    }

    const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
    //const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error

    ReactDOM.render(foo, document.getElementById('root'));

</script>
```

続きは次回。

# React JSX Tip: Accept a component that can act on props and be rendered using JSX

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# React JSX Tip: Generic components

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# Generic functions

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# React Tip: Strongly Typed Refs

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# Type Assertions

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# Default Props

```html:index.html
<!-- 省略 -->
<script type="text/babel">
    // 次回
</script>
```

# 感想

- 調べながらだと時間かかる
- 型がある世界は良い
- 日本語の情報少ない？

以上