34
loading...
This website collects cookies to deliver better user experience
# with npm
npm install --save mobx mobx-react-lite
# or with yarn
yarn add mobx mobx-react-lite
./src/store/index.ts
export class RootStore {
classes: ClassesStore;
constructor() {
this.classes = new ClassesStore();
}
}
export const rootStore = new RootStore();
RootStore
is just a container for other stores. In our case we have only ClassesStore
, but in real world we'll have more. Likeexport class RootStore {
classes: ClassesStore;
user: UserStore;
settings: SettingsStore;
...
}
ClassesStore
base to the ./src/store/ClassesStore.ts
export type ClassItemType = {
id: number;
title: string;
}
export class ClassesStore {
items: ClassItemType[] = [];
}
rootStore
instance with React Context./**
* ./src/store/index.ts
**/
import { createContext, useContext } from "react";
...
export const StoreContext = createContext(rootStore);
export const StoreProvider = StoreContext.Provider;
export const useStore = () => useContext(StoreContext);
StoreProvider
/**
* ./App.ts
**/
...
import { rootStore, StoreProvider } from "./src/store";
export default function App() {
...
return (
<StoreProvider value={rootStore}>
<PaperProvider theme={theme}>
<SafeAreaProvider>
<Navigation theme={theme} />
<StatusBar style={isDark ? "light" : "dark"} />
</SafeAreaProvider>
</PaperProvider>
</StoreProvider>
);
}
useStore
hook./**
* ./src/screens/HomeScreen.tsx
**/
...
export const HomeScreen = ({navigation}: Props) => {
const rootStore = useStore();
return (
<View style={styles.container}>
<ScrollView>
{rootStore.classes.items.map((item) => {
return (
<View key={`${item.id}`} style={{marginBottom: 15}}>
<ClassItem title={item.title} onPress={() => {
navigation.navigate(routes.EDIT_CLASS, {
classItem: item
})
}}/>
</View>
);
})}
</ScrollView>
...
</View>
);
}
ClassesStore
items./**
* ./src/store/ClassesStore.ts
**/
export class ClassesStore {
items: ClassItemType[] = [];
...
updateItem(newItem: ClassItemType) {
const foundItem = this.items.find(item => item.id === newItem.id);
if (foundItem) {
this.items = this.items.map(item => {
if (item.id === newItem.id) {
return newItem;
}
return item;
})
} else {
this.items = [...this.items, newItem];
}
}
deleteItem(itemToRemove: ClassItemType) {
this.items = this.items.filter(item => item.id !== itemToRemove.id);
}
}
classes
from useStore
hook. On delete function we run classes.deleteItem(item)
and on save we do classes.updateItem(newItem)
./**
* ./src/screens/EditClassScreen.tsx
**/
...
export const EditClassScreen =
({navigation, route}: EditClassScreenProps) => {
const item = route.params?.classItem ?? {
id: new Date().getTime(),
title: '',
};
const { classes } = useStore();
...
const onDelete = () => {
classes.deleteItem(item);
navigation.goBack();
}
const onSave = () => {
if (!title) {
setError(true);
} else {
classes.updateItem({
id: item.id,
title,
})
navigation.goBack();
}
};
...
;
ClassesStore
for observable with makeAutoObservable
function/**
* ./src/store/ClassesStore.ts
**/
...
import { makeAutoObservable } from "mobx";
export class ClassesStore {
...
constructor() {
makeAutoObservable(this);
}
...
}
observer
function like this/**
* ./src/screens/HomeScreen.tsx
**/
...
import { observer } from "mobx-react-lite";
...
export const HomeScreen = observer(({navigation}: Props) => {
...
});
rootStore
and AsyncStorage
/**
* ./src/store/index.ts
**/
...
import { AsyncTrunk } from 'mobx-sync';
import AsyncStorage from '@react-native-async-storage/async-storage';
...
export const trunk = new AsyncTrunk(rootStore, {
storage: AsyncStorage,
})
...
/**
* ./App.tsx
**/
...
import { rootStore, StoreProvider, trunk } from "./src/store";
export default function App() {
...
useEffect(() => {
const rehydrate = async () => {
await trunk.init();
setIsStoreLoaded(true);
}
rehydrate();
}, []);
if (!isLoadingComplete || !isStoreLoaded) {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<ActivityIndicator size="large" />
</View>
);
} else {
return (
...
{/** Our app components tree here */}
...
);
}
}