React.Hooksを使ってlocal stateを持つstatefulなfunctional Componentを触ってみる


:writing_hand: [React Hooks](https://reactjs.org/docs/hooks-intro.html)

> Hooks are a new feature proposal that lets you use state and other React features without writing a class. They’re currently in React v16.7.0-alpha and being discussed in an open RFC.

もうちょっとしたらclass構文を使わずにfunctional componentの中でもstateを扱ったり各レンダリングサイクルに干渉出来るようになるようです。

## [useState](https://reactjs.org/docs/hooks-overview.html#-state-hook)

class構文でやってた`this.state`と`this.setState`の部分の切り出し

```bash:提供されているversion(16.7.0-alpha.0)でsetup
$ mkdir react-useState && cd $_ 
$ mkdir pages && touch pages/index.js && yarn init --yes
$ yarn add react@16.7.0-alpha.0 react-dom@16.7.0-alpha.0 next
```

```jsx:pages/index.js
import { useState } from "react";

export default () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
};
```

```bash:起動
$ ./node_modules/.bin/next
```

```jsx:等価のコードを書く為にこれまではlocalstateを持つclassを作る必要があって記述量も結構あった
export default class Example extends React.Component {
  state = {
    count: 0,
  };

  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={this.handleChange}>Click me</button>
      </div>
    );
  }
}

```

```jsx:こういうテクも紹介されてた
import { useState } from "react";

function useFormInput(initValue) {
  const [value, setValue] = useState(initValue);

  const handleChange = e => {
    setValue(e.target.value);
  };

  return {
    value,
    onChange: handleChange,
  };
}

export default () => {
  const name = useFormInput("lidqqq");

  return (
    <input {...name} />
  );
};
```

こんな感じでカスタムフックを作る場合は関数名のprefixに`use`を付けるべしとの公式見解。

## [useEffect](https://reactjs.org/docs/hooks-overview.html#%EF%B8%8F-effect-hook)

class構文内の`componentDidMount, componentDidUpdate, componentWillUnmount`内でやってたやつの切り出し

```jsx:pages/index.js
import { useState, useEffect } from "react";

export default () => {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
};
```

`useEffect`を使うことで、今まで各ライフサイクル単位でその中にどっかりと記述していたロジックを、コンポーネント内に複数のエフェクトを記述して関連する部分ごとに分割できるようです。

```jsx:
import { useState, useEffect } from "react";

function useWindowWidth() {
  if (process.browser) {
    const [width, setWidth] = useState(window.innerWidth);
    useEffect(() => {
      const handleResize = () => setWidth(window.innerWidth);
      window.addEventListener("resize", handleResize);
      return () => {
        window.removeEventListener("resize", handleResize);
      };
    });
    return width;
  }
}

export default () => {
  const width = useWindowWidth();

  return (
    <div>
      {width}
    </div>
  );
};
```

## Hookのルール

- トップレベルでのみフックを呼び出す。ループやif文、ネストされた関数内でフックを呼び出さない。
- Reactを利用していないnativeなJavaScript関数からフックを呼び出さない。

[eslintのルール](https://www.npmjs.com/package/eslint-plugin-react-hooks)があるらしいのでそれ使いましょうとのこと。

その他は後日書く（多分書く）

:moyai: 「Formの度にControlled Componentsに苦しめられていた...」