まえがき
この記事は根本的な部分については未解決の記事になります。
原因は解明できてませんが、こういう現象があったという覚書きです。
環境
next @7.0.1
react @16.5.2
redux @4.0.0
react-redux @5.0.7
recompose @0.30.0
- nextでSSRしている
- jsonで保持しているデータをfetchしてページを生成
やりたかったこと
ハッシュ付きのURLでアクセスした際にアンカーが作動して当該IDの箇所に画面が移動する
要は http://foo.bar#bazz
が効くようにしたい。
発生した問題
1.普通にIDを指定して飛ばして見た
上手く遷移せず。
おそらくDOMが生成される前に飛ぼうとして、飛び先が見つかってないのかな?
2.componentDidMountでハッシュを見て処理してみる
lifecycle({
componentDidMount() {
if (location.hash) {
const elem = document.getElementById(location.hash.slice(1))
if (elem) {
elem.scrollIntoView({
behavior: 'auto',
})
}
}
}
})
動かない。どうして...
componentDidMount
なんだからこのタイミングでDOM生成されていて、elem
も見つかるはずじゃないのかな?
3.とりあえずsetTimeoutを入れてみる
lifecycle({
componentDidMount() {
if (location.hash) {
setTimeout(() => {
const elem = document.getElementById(location.hash.slice(1))
if (elem) {
elem.scrollIntoView({
behavior: 'auto',
})
}
}, 1000)
})
}
})
動いた。どうして...
componentDidMount
から1000msに発火するように調整。なぜか動く。
ちなみに100msとかにすると動かない。
この1000msの間に何があるのだ...
4.onload eventにしてみる
lifecycle({
componentWillMount() {
this.props.onBeforeMount()
},
componentDidMount() {
if (location.hash) {
window.addEventListener('load', () => {
const elem = document.getElementById(location.hash.slice(1))
if (elem) {
elem.scrollIntoView({
behavior: 'auto',
})
}
})
}
}
})
これは動かない。
やってる方もよくわかってないけどcomponentDidMount
のタイミングでonload
イベントを入れてみた。
onload
って全て読み込みが終わったあとに発火するのではないの...?どうしてelemが取得できないんだろう。
5.最終的にこうなった
lifecycle({
componentDidMount() {
if (location.hash) {
window.addEventListener('load', () => {
setTimeout(() => {
const elem = document.getElementById(location.hash.slice(1))
if (elem) {
elem.scrollIntoView({
behavior: 'auto',
})
}
}, 0)
})
}
}
})
もはや意味がわからない。
componentDidMount
のタイミングでonload
イベントとしてsetTimeout(fn, 0)
の関数を設定すると動く。
6.どうしてこうなった?
結果をまとめてみる。
設定 | 結果 |
---|---|
componentDidMountのみ | 動かない |
setTimeout 1000ms | 動く |
setTimeout 0ms | 動かない |
onload | 動かない |
onload + setTimeout 0ms | 動く |
よくわからない点がいくつか。
-
componentDidMount
だけで動かないのはなぜ?コンポーネントがマウントされたあとに発火するから動くはずなのでは? -
onload
で動かないのはなぜ?全ての要素が(ry -
setTimeout(fn, 0)
はなんとなく後述のような理由で意味があるのかな?
setTimeout(fn, 0)について
setTimeout
は4msの遅延が発生する
setTimeout
は他処理が終わるまでスタックされる
最後にsetTimeout
0msを入れて動いたのはどっちの仕様の影響なんだろう?
どちらにしても、onload
から4msの間に何かあるんだろうなぁ...?
まとめ
世の中には不思議なことがいっぱいあるんだなぁ(
こういう根本的な問題が発生した時に、やっぱり仕様を読めた方が良いよなぁと思うので英語を勉強しようと思いましたまる。