Skip to content

Instantly share code, notes, and snippets.

@thecodecafe
Last active September 22, 2022 05:15
Show Gist options
  • Save thecodecafe/6ee3637ad7d569fdd4ebf7c4c60ead5f to your computer and use it in GitHub Desktop.
Save thecodecafe/6ee3637ad7d569fdd4ebf7c4c60ead5f to your computer and use it in GitHub Desktop.
Async Storage Exercise
import React, {useCallback, useEffect, useState} from 'react';
import {
ActivityIndicator,
Alert,
Button,
StyleSheet,
Text,
View,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {IAppProps} from './interfaces';
const EN: Record<string, string> = {
greeting: 'Hello',
alert_title: 'Select language',
alert_option_1_text: 'Set language to Spanish',
alert_option_2_text: 'Do nothing',
success_title: 'Success',
success_message: 'Idioma cambiado con éxito a español.',
button: 'Choose favorite color',
color_alert_title: 'Select a color',
color_alert_option_1: 'Orange',
color_alert_option_2: 'Green',
color_alert_cancel: 'Cancel',
no_color_selected: 'No color selected.',
};
const ESP: Record<string, string> = {
greeting: 'Hola',
alert_title: 'Seleccione el idioma',
alert_option_1_text: 'Establecer idioma en inglés',
alert_option_2_text: 'Hacer nada',
success_title: 'Éxito',
success_message: 'Language successfully changed to English.',
button: 'Elige color favorito',
color_alert_title: 'Selecciona un color',
color_alert_option_1: 'Orange',
color_alert_option_2: 'Green',
color_alert_cancel: 'Cancelar',
no_color_selected: 'Ningún color seleccionado.',
};
const App: IAppProps = function App() {
const [color, setColor] = useState<string>();
const [language, setLanguage] = useState<string>();
const [translation, setTranslation] = useState<Record<string, string>>();
const handleChangeLanguage = useCallback(async () => {
// we will switch to the other language or maintain english if non is selected
const newLanguage = language === 'EN' ? 'ESP' : 'EN';
// we will select a translation depending on what language is selected as new language
const newTranslation = newLanguage === 'EN' ? ESP : EN;
// store the new language in async storage
await AsyncStorage.setItem('LOCATION', newLanguage);
// find the selected language's favorite color in async storage
const languageColor = await AsyncStorage.getItem(
`FAVORITE_COLOR:${newLanguage}`,
);
// update state with new language
setLanguage(newLanguage);
// update state with language color
setColor(languageColor || undefined);
// update state with selected translation
setTranslation(newTranslation);
}, [language]);
const handleButtonPress = useCallback(() => {
// if translation is not set stop
if (!translation) {
return;
}
// ask user to switch language
Alert.alert(translation.alert_title, '', [
{text: translation.alert_option_1_text, onPress: handleChangeLanguage},
{text: translation.alert_option_2_text, style: 'cancel'},
]);
}, [handleChangeLanguage, translation]);
const chooseColor = useCallback(
async (selectedColor: string) => {
// if language is not set stop
if (!language) {
return;
}
// save color of selected language in async storage
// Example: Selecting EN will result in the following async storage key FAVORITE_COLOR:EN
await AsyncStorage.setItem(`FAVORITE_COLOR:${language}`, selectedColor);
// update state with selected color
setColor(selectedColor);
},
[language],
);
const handleChooseColor = useCallback(() => {
// if translation is not set stop
if (!translation) {
return;
}
// ask user to select color
Alert.alert(translation.color_alert_title, '', [
{
text: translation.color_alert_option_1,
onPress: () => chooseColor('Orange'),
},
{
text: translation.color_alert_option_2,
onPress: () => chooseColor('Green'),
},
{text: translation.color_alert_cancel, style: 'cancel'},
]);
}, [chooseColor, translation]);
const initialize = useCallback(async () => {
// get saved color at component initialization
const persistedLanguage: string | null = await AsyncStorage.getItem(
'LANGUAGE',
);
// check if a language was saved
if (persistedLanguage) {
// get the saved color for the saved language
const languageColor = await AsyncStorage.getItem(
`FAVORITE_COLOR:${persistedLanguage}`,
);
// update state with saved color
setColor(languageColor || undefined);
}
// update sate with saved language
setLanguage(persistedLanguage || 'EN');
// update state with saved language's translation
setTranslation(persistedLanguage === 'ESP' ? ESP : EN);
}, []);
useEffect(function componentDidMount() {
// initialize component after 2 seconds (simulate an async call)
setTimeout(initialize, 2000);
return function componentWillUnmount() {
// do nothing for now
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// render a loader if no translation has been set
if (!translation) {
return (
<View style={styles.container}>
<ActivityIndicator
style={styles.contentLoader}
size="large"
color="#666666"
/>
</View>
);
}
// render content if translation has been set
return (
<View style={styles.container}>
<Button title={translation.greeting} onPress={handleButtonPress} />
<Button title={translation.button} onPress={handleChooseColor} />
<Text style={styles.colorName}>
{color || translation.no_color_selected}
</Text>
</View>
);
};
const styles = StyleSheet.create({
colorName: {
textAlign: 'center',
marginVertical: 40,
},
contentLoader: {
alignSelf: 'center',
},
container: {
marginVertical: 100,
justifyContent: 'center',
paddingHorizontal: 24,
},
});
export default App;
import React from 'react';
export type IAppProps = React.FC<{}>;
import {createContext} from 'react';
import {ILocationContext} from './interfaces';
export const LocationContext = createContext<ILocationContext>({});
import AsyncStorage from '@react-native-async-storage/async-storage';
import React, {useCallback, useEffect, useState} from 'react';
import {ILocation, ILocationProviderProps, IWeatherReport} from './interfaces';
import {LocationContext} from './LocationContext';
const LocationProvider: ILocationProviderProps = function LocationProvider({
children,
}) {
const [location, setLocation] = useState<ILocation>();
const [weatherReport, setWeatherReport] = useState<IWeatherReport>();
const initialize = useCallback(async () => {
// get saved color at component initialization
const persistedLocationRaw: string | null = await AsyncStorage.getItem(
'LOCATION',
);
// JSO parse weather report if found
const persistedLocation: ILocation | undefined = persistedLocationRaw
? JSON.parse(persistedLocationRaw)
: undefined;
// check if a language was saved
if (persistedLocation) {
// get the saved color for the saved language
const persistedWeatherReportRaw: string | null =
await AsyncStorage.getItem(
`FAVORITE_COLOR:${persistedLocation.country}:${persistedLocation.state}`,
);
// JSON part weather report if found
const persistedWeatherReport: IWeatherReport | undefined =
persistedWeatherReportRaw
? JSON.parse(persistedWeatherReportRaw)
: undefined;
// update state with saved color
setWeatherReport(persistedWeatherReport || undefined);
}
// update sate with saved language
setLocation(persistedLocation || undefined);
}, []);
useEffect(function componentDidMount() {
// initialize component after 2 seconds (simulate an async call)
setTimeout(initialize, 2000);
return function componentWillUnmount() {
// do nothing for now
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<LocationContext.Provider
value={{
location,
weatherReport,
setLocation,
setWeatherReport,
}}>
{children}
</LocationContext.Provider>
);
};
export default LocationProvider;
import React from 'react';
export type ILocationProviderProps = React.FC<{
children: React.ReactNode;
}>;
export type ILocation = {
country: string;
state: string;
};
export type IWeatherReport = any;
export type ILocationContext = {
location?: ILocation;
weatherReport?: IWeatherReport;
setLocation?: (location: ILocation) => void;
setWeatherReport?: (weatherReport: IWeatherReport) => void;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment