'Mobx React Return Store without Component
I am trying to build a function where I can switch languages in my store and use different json files based on return value from a hook.
Here is my store:
import AsyncStorage from '@react-native-async-storage/async-storage';
import { action, computed, makeObservable, observable } from 'mobx';
import { makePersistable } from 'mobx-persist-store';
import { IAppConfig } from '../models/IAppConfig';
import { LanguageType } from '../models/IAppConfig';
import { ILanguage } from '../models/ILanguage';
class AppConfig {
appConfig: IAppConfig = {
language: {
id: 0,
lang: LanguageType.ru,
title: 'RU'
}
};
constructor() {
makeObservable(this, {
appConfig: observable,
changeLang: action,
language: computed
});
makePersistable(this, {
name: 'AppConfig',
storage: AsyncStorage,
expireIn: 86400000,
properties: ['appConfig']
});
}
changeLang(lang: ILanguage) {
this.appConfig.language = lang;
}
get language() {
return this.appConfig.language;
}
}
export const configStore = new AppConfig();
here is the screen component:
function ProfileScreen() {
const { TEXT } = useComponent();
const setLangRu = () => {
const lang: ILanguage = { id: 0, lang: LanguageType.ru, title: 'russian' };
configStore.changeLang(lang);
};
const setLangEn = () => {
const lang: ILanguage = {id: 1,lang: LanguageType.en,title: 'english'};
configStore.changeLang(lang);
};
return (
<View style={styles.container}>
<Text>{TEXT.HOME.HELLO}</Text>
<Observer>
{() => <Text>language is {configStore.language.title}</Text>}
</Observer>
<View style={{ flexDirection: 'row' }}>
<BouncedTouchable style={styles.button} onPress={() => setLangRu()}>
<Text>RU</Text>
</BouncedTouchable>
<BouncedTouchable style={styles.button} onPress={() => setLangEn()}>
<Text>EN</Text>
</BouncedTouchable>
</View>
</View>
);
}
and the useText hook which returns dictionary:
import { LanguageType } from '../models/IAppConfig';
import { en } from '../config/lang/en';
import { ru } from '../config/lang/ru';
import { configStore } from '../store/AppConfig';
const useText = () => {
const locale = configStore.language.lang;
switch (locale) {
case LanguageType.en:
return en;
case LanguageType.ru:
return ru;
default:
return ru;
}
};
export default useText;
The problem is that it is not reactive: the changes in useText's locale variable are not computed reactively (after refresh everything is ok). I have tried using this:
const locale = useObserver(() => configStore.language.lang);
but it says that useObserver is deprecated (even though everything works fine). I don't want to wrap the whole screen in observer so what should I do to get react store in locale?
Solution 1:[1]
I have created a hook that returns my state.
useSelector hook:
import { autorun } from 'mobx';
import { useEffect, useState } from 'react';
export function useSelector(select: any) {
const [selected, setSelected] = useState(select);
useEffect(() => autorun(() => setSelected(select())), []);
return selected;
}
In any component call your store (just like Redux), the example here is the one with the question above:
const locale: LanguageType = useSelector(() => AppConfig.language.lang);
now if I change the locale in any of my screen, the language changes automatically without restarting the app.
Solution 2:[2]
If you want to optimize your view component, then you can create two components or try to dereference values later.
So if you stick with the first approach, then your component with language.title would like this:
const MyComponent = observer(({ language }) => (
<div>
<Text>language is {language.title}</Text>
</div>
))
Another way is to create generic function which takes a parameter to show data. The code would like that:
const GenericDisplayer = observer(({ getName }) => <DisplayName name={getName()} />)
and then use in your application:
const YourComponent = ({ language }) => (
<>
<GenericDisplayer getName={() => person.name} />
</>
)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | denistepp |
| Solution 2 | StepUp |
