JavaScript
reactjs
React

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

:writing_hand: React Hooks


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

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


提供されている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


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



起動

$ ./node_modules/.bin/next



等価のコードを書く為にこれまでは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>
);
}
}



こういうテクも紹介されてた

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

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


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

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のルールがあるらしいのでそれ使いましょうとのこと。

その他は後日書く(多分書く)

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