よくあるパターンとして、3項間演算子を使った以下のようなパターンがあります。
this.state.isLoading ? <Loading /> : (
<div>
<div>
<MyComponent1 />
</div>
<div>
<MyComponent2 />
</div>
<div>
<MyComponent3 />
</div>
<div>
<MyComponent4 />
</div>
</div>
)
しかし、どちらを先に書くか?等の不要な判断が入るスキマが残っています。
例えば、以下の場合はローディング中にMyCompコンポーネントが表示されてしまうでしょう。
this.state.isLoading ? <MyComp /> : <Loading />
このような場合、ローディングを抽象したコンポーネントを用意してあげると便利です。
MyComponentは必ずローディング後にレンダリングされることが保証されます。
<SwitchLoading isLoading={this.state.isLoading}>
<MyComponent />
</SwitchLoading>
やり方は色々ありますが、シンプルにこんな感じで用意して上げればいいと思います。
ここでは、更にMaybeコンポーネントを用意しています。
もちろん、flowを使わない理由はないですから、flowで型付けを行います。
// @flow
import * as React from 'react'
class Maybe extends React.Component<{
flag: boolean,
children?: React.Node,
else: React.Node,
}> {
render() {
const { props } = this
return props.flag ? props.children : props.else
}
}
const Loading = () => <div>Loading...</div>
class SwitchLoading extends React.Component<{
isLoading: boolean,
children?: React.Node,
}> {
render() {
const { props } = this
return (
<Maybe flag={props.isLoading} else={<Loading />}>
{props.children}
</Maybe>
)
}
}
const MyComponent = () => <h2>Hello World</h2>
class App extends React.Component<{}, { isLoading: boolean }> {
state = { isLoading: false }
componentDidMount() {
setTimeout(() => {
this.finishLoading()
}, 2000)
}
finishLoading = () => {
this.setState({ isLoading: true })
}
render() {
const { state } = this
return (
<div className="App">
<SwitchLoading isLoading={state.isLoading}>
<MyComponent />
</SwitchLoading>
</div>
)
}
}
export default App
🤔
VS HoC
withLoadingのようなHoCを用意してあげてもいいです。
が、しかし、HoCは便利な反面、複雑で厄介です。
個人的にはパフォーマンス上の理由がない限り、自分でHoCを作成するのは避けます。
どちらかと言えば、コントロール可能なコンポーネントを作る場合、Comp as Funcスタイル(react-motion等)か、レンダラーpropスタイルを使う方が単純で便利だと思います。