ReactNativeで複数画面間の共通変数を扱うことを考える。
共通の定数ならグローバルで用意して読み込めばいいけど変数は少し厄介だった。
複数画面の管理はReact Navigation、設定保存などにはAsyncStorageを使う。
React Native 0.60 Expo v34 react-navigation 3.12.0
グローバル変数を使う
参照はグローバル定義から行う。
テーマカラーを共通変数として管理します。
1 2 3 |
export const lightTheme = {...}; export const darkTheme = {...}; export let color = lightTheme; |
設定用関数を作りつつファイル読み込み時にグローバル変数を設定する。
1 2 3 4 5 6 7 8 9 |
export const setTheme = async () => { let v = await AsyncStorage.getItem("setting_theme"); if (v == "dark") { Global.color = Global.darkTheme; } else { Global.color = Global.lightTheme; } }; setTheme(); //ファイル読み込み時実行 |
また設定する関数も作っておく。
1 2 3 4 |
export const saveTheme = async v => { await AsyncStorage.setItem("setting_theme", v); setTheme(); }; |
グローバル変数を変えても再描写は行われないためどこかで再描写する必要がある。
react-navigationを使っているのでフォーカスが合うたびに再描画されるようにwillFocusイベントを使う。
1 2 3 4 5 6 7 8 9 10 |
constructor(props) { super(props); ... this.subs = [this.props.navigation.addListener("willFocus", this.componentWillFocus)]; } componentWillFocus = async () => { this.forceUpdate(); ... } |
非推奨ではあるけどforceUpdate()
で強制再描画する。
問題点
とにかく管理がめんどくさい。
必要のない再描画が入る、またタイミングの問題か若干不安定な描画になった。
screenPropで管理する
React Navigationを改造してプロパティーを渡す。
screenPropを通して各スクリーンに値渡しが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const TabNavigator = createBottomTabNavigator({...}) export defaultcreateAppContainer(TabNavigator); ↓ const AppContainer = createAppContainer(TabNavigator); export default class App extends React.Component { constructor(props) { super(props); this.state = { color: Global.lightTheme, setTheme: this.setTheme }; this.setTheme(); } setTheme = () => { Storage.getColors().then(c => { this.setState({ color: c }); }); }; render() { return <AppContainer screenProps={this.state} />; } } |
Screen側ではthis.props.screenProps
でアクセスできる。
this.props.screenProps.setTheme()
で変更した場合全てのスクリーンが再描画。
設定画面ではAsyncStorage
の管理とこの関数呼び出しだけ。だいぶ楽になった。
そもそもReduxで集中管理すれば楽になる気がする。また1から使ってみるか。