いくつかのグローバルな価値と機能を共有するための最良の方法は何ですか?
今私はそれらすべての中に1つのContextProviderを持っています:
<AllContext.Provider
value={{
setProfile, // second function that changes profile object using useState to false or updated value
profileReload, // function that triggers fetch profile object from server
deviceTheme, // object
setDeviceTheme, // second function that changes theme object using useState to false or updated value
clickEvent, // click event
usePopup, // second function of useState that trigers some popup
popup, // Just pass this to usePopup component
windowSize, // manyUpdates on resize (like 30 a sec, but maybe can debounce)
windowScroll // manyUpdates on resize (like 30 a sec, but maybe can debounce)
}}
>
しかし、悲しいように docs :コンテキストは参照IDを使用していつ再レンダリングするかを決定するため、プロバイダーの親が再レンダリングすると、コンシューマーで意図しないレンダリングをトリガーする可能性のある問題がいくつかあります。たとえば、新しいオブジェクトは常に値に対して作成されるため、次のコードは、プロバイダーが再レンダリングするたびにすべてのコンシューマーを再レンダリングします。
これは悪いです:
<Provider value={{something: 'something'}}>
これで結構です:
this.state = {
value: {something: 'something'},
};
<Provider value={this.state.value}>
将来的には最大30のコンテキストプロバイダーが存在すると思いますが、あまり友好的ではありません:/
では、このグローバル値と関数をコンポーネントに渡すにはどうすればよいですか?できます
プロバイダーで使用するものの例:
// Resize
const [windowSize, windowSizeSet] = useState({
innerWidth: window.innerWidth,
innerHeight: window.innerHeight
})
// profileReload
const profileReload = async () => {
let profileData = await fetch('/profile')
profileData = await profileData.json()
if (profileData.error)
return usePopup({ type: 'error', message: profileData.error })
if (localStorage.getItem('deviceTheme')) {
setDeviceTheme(JSON.parse(localStorage.getItem('deviceTheme')))
} else if (profileData.theme) {
setDeviceTheme(JSON.parse(JSON.stringify(profileData.theme)))
} else {
setDeviceTheme(settings.defaultTheme)
}
setProfile(profileData)
}
// Click event for menu close if clicked outside somewhere and other
const [clickEvent, setClickEvent] = useState(false)
const handleClick = event => {
setClickEvent(event)
}
// Or in some component user can change theme just like that
setDeviceTheme({color: red})
あなたはまだそれらを組み合わせることができます!パフォーマンスが心配な場合は、オブジェクトを先に作成できます。使用する値が変化するかどうかはわかりませんが、変化しない場合は非常に簡単です。
state = {
allContextValue: {
setProfile,
profileReload,
deviceTheme,
setDeviceTheme,
clickEvent,
usePopup,
popup,
windowSize
}
}
render() {
return <AllContext.Provider value={this.state.allContextValue}>...</AllContext>;
}
ただし、実行する必要がある値を更新したいときはいつでも、次のようにします。
this.setState({
allContextValue: {
...this.state.allContextValue,
usePopup: true,
},
});
これはパフォーマンスが高く、比較的簡単でもあります:)それらを分割すると少しスピードアップするかもしれませんが、実際に遅くなるとすぐに、そして多くの消費者。
それでも、あなたの価値があまり変わらなければ、心配することは何もありません。