useEffect系はコンポネント順ではない
考えてみると当たり前だが、順番的には子コンポーネントのレンダリング準備が整ってから親コンポーネントのレンダリングに取り掛かる
なので、親のuseEffectやuseLayoutEffectは子コンポーネントのそれらが終えてから実行される
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, {useState, useLayoutEffect, createContext, useContext} from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
const StateContext = createContext({})
const App = () => {
const [state, setState] = useState([])
useLayoutEffect(() => {
console.log("parent layout effect")
setState((currentState) => [...currentState, "parent"])
}, [])
const stateContextProps = {
state: state,
setState: setState
}
console.log("parent")
console.log(state)
return (
<StateContext.Provider value={stateContextProps}>
<ChildComponent name="child1"/>
<ChildComponent name="child2"/>
<ChildComponent name="child3"/>
</StateContext.Provider>
)
}
const ChildComponent = ({name}) => {
const stateContext = useContext(StateContext)
useLayoutEffect(() => {
console.log(name + " layout effect")
stateContext.setState((currentState) => [...currentState, name])
}, [])
console.log(name)
return (
<div> {name} </div>
)
}
ReactDOM.render(<App />, document.querySelector('#app'))
↓ 実行ログ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"parent"
// [object Array] (0)
[]
"child1"
"child2"
"child3"
"child1 layout effect"
"child2 layout effect"
"child3 layout effect"
"parent layout effect"
"parent"
// [object Array] (4)
["child1","child2","child3","parent"]
"child1"
"child2"
"child3"
実行順は親→子コンポーネント(親のreturn内で初めて子コンポーネントが呼ばれるので)
にもかかわらず、useLayoutEffect
の順は子→親。
親は子の最後にuseEffectされる点に注意
useContextでsetStateを渡して子コンポーネント内で親のstateを操作するような場合、親の操作するタイミングには注意する必要があるようです。
例えば親→子の順にstateに値を追加していきたい場合は、親が最後に呼ばれるので、下記のように親を先頭に追加するよう記載する必要があります。
1
2
3
4
useLayoutEffect(() => {
console.log("parent layout effect")
setState((currentState) => ["parent", ...currentState])
}, [])
↓ 実行ログ
1
2
// [object Array] (4)
["parent","child1","child2","child3"]