解決策
useEffect の第2引数に空配列を指定すれば良い。
useEffect(() => {}, []);
詳細
空の配列 [] を渡すと、この副作用がコンポーネント内のどの値にも依存していないということを React に伝えることになります。つまり副作用はマウント時に実行されアンマウント時にクリーンアップされますが、更新時には実行されないようになります。
つまり、componentDidMount と componentWillUnmount のときのみ実行される挙動と近くなる。
実例
この例では、DOMの <input type="hidden"> に埋め込まれている JSON を componentDidMount のタイミングで処理している。一部TypeScriptで書かれている。
import React, {useState, useEffect} from 'react';
import ReactDOM from 'react-dom';
function unescapeQuote(str: string): string {
let div = document.createElement('div');
div.innerText = str;
// unescape
return div.innerText;
}
export default function Example() {
let [data, setData] = useState({});
useEffect(() => {
let jsonDataString: string = '';
const jsonDataElement: HTMLInputElement = document.getElementById('json-data') as HTMLInputElement;
if (jsonDataElement) {
jsonDataString = jsonDataElement.value;
}
const matome = JSON.parse(unescapeQuote(jsonDataString));
if (matome) {
setData(matome);
}
}, []); // only componentDidMount
return (
<div className="container">
<div className="row justify-content-center">
<div className="col-md-8">
<div className="card">
<div className="card-header">Example Component</div>
<div className="card-body">I'm an example component!</div>
</div>
</div>
</div>
</div>
);
}
if (document.getElementById('example')) {
ReactDOM.render(<Example/>, document.getElementById('example'));
}