Using activeStorage with i18n on expo not working - reactjs

Trying to set an app using Typescript React on expo that can show a different language based on a user selection, but doesn't seem to be working.
I've made it store the selected language in asyncStorage and called await AsyncStorage.getItem('language') to get the language, my code is below. If console.log is run on asyncStorage, I was able to retrieve the value.
Interestingly, language works without any flaws when I use Localization.locale, so wondering if it's being asyncStorage is taking too long to get a result?
import I18n from 'i18n-js'
import AsyncStorage from '#react-native-community/async-storage'
import en from './en.json'
import zh from './zh.json'
I18n.translations = {
en,
zh
}
async function getLanguage() {
try {
const value = await AsyncStorage.getItem('language')
if (value != null) {
I18n.locale = value.slice(0,2)
I18n.fallbacks = true
}
} catch(e) {
console.log(e)
}
}
getLanguage()
export function t(name: string) {
return I18n.t(name)
}
Language selector (stores the selected language in asyncStorage)
import AsyncStorage from '#react-native-community/async-storage'
import { Updates } from 'expo';
export default function LanguageChange() {
const onPress = async (language: string) => {
await AsyncStorage.setItem('language', language);
Updates.reload();
}
return (
<View style={styles.languageContainer}>
<TouchableOpacity onPress={() => onPress("en")}>
<Text>English</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => onPress('zh-CN')}>
<Text>Chinese</Text>
</TouchableOpacity>
</View>
);
}
Edit 1
I've tried using .then as well to see if there was a different result, but it's still the same.
AsyncStorage.getItem('language').then((result) => {
I18n.locale = result.slice(0,2)
})

Related

How can I press individual option in actionsheet in React Native?

I am still new to React Native. I have an actionsheet with two options and a cancel option. I am having trouble understanding how to make each option do something different when pressed.
My code:
import React, { useRef } from "react"
import ActionSheet from 'react-native-actionsheet'
import { View, Text, Pressable } from "react-native";
import Icon from 'react-native-vector-icons/FontAwesome';
const ActionSheet = () => {
let actionSheet = useRef();
let optionArray = ['Orange', 'Cherry', 'Cancel'];
const showActionSheet = () => {
actionSheet.current.show();
}
return (
<View
<Pressable onPress={showActionSheet}>
<View>
<Text>Choose Fruit</Text>
<Icon name="angle-right" size={15}/>
</View>
</Pressable>
<ActionSheet
ref={actionSheet}
options={optionArray}
cancelButtonIndex={2}
onPress={{????}}
/>
</View>
);
};
What I'd like to do is navigate to a different screen when an option is pressed
Would appreciate any help. Thank you in advance!
The onPress function provides an index argument. Thus consider the following code snippet.
const onActionSelect = (index) => {
if (index === 1) {
// first action pressed
} else if (index === 2) {
// second action pressed
}
// and so on
}
<ActionSheet
ref={actionSheet}
options={optionArray}
cancelButtonIndex={2}
onPress={onActionSelect}
/>

React useSelector not working, what am I doing wrong?

I have a selectors folder with the selector.js file
const isRecipeFavorited = state => recipeId => {
const recipe = state.find(recipe => recipe.id === recipeId)
console.log(`Selector isRecipeFavourtied: ${recipeId}`)
return recipe ? recipe.is_fav : false
}
This is my favicon.js file which calls this useSelector.
import React, {useState, useEffect} from 'react'
import { FontAwesome } from '#expo/vector-icons'
import { View, TouchableOpacity,StyleSheet, Text, Alert } from 'react-native'
import {isRecipeFavorited} from '../selectors/selectors'
import {useSelector} from 'react-redux'
import { favids } from '../reducers/favids'
const FavIcon = ({recipeid, onToggle, isFavourite, text}) => {
const isFavNew = useSelector(isRecipeFavorited(recipeid))
return (
<View>
<TouchableOpacity style={styles.favItem} onPress={() => onToggle(recipeid)}>
<FontAwesome name={isFavNew === true ? 'heart' : 'heart-o'} size={40} color='red' />
<Text> {text}</Text>
</TouchableOpacity>
</View>
)
}
export default FavIcon
I keep getting an error saying my selector is not a function. _selectors.isRecipeFavourited is not a function.
I am trying to retrieve the value of the recipe.is_fav from the state.
I am also using Redux in this project.
I think you need to reverse state and recipeId in your selector function, i.e.:
const isRecipeFavorited = recipeId => state => {...}
This is a valid useSelector:
const thing = useSelector(state => state.thing);
In your case, you're calling a function with another type of argument, which in turn should return a function of the type that useSelector is expecting.
This is solved by drilling down into the favids object.
The selector function has been modified as below.
const recipe = state.favids.find(recipe => recipe.recipeid === recipeId)
return recipe ? recipe.is_fav : false
}```

This.refs for functional components (useRef, createRef) | React native

I have used this.refs on a class component and now I am refactoring it to be a functional component. I am using the ViewShot lib: https://github.com/gre/react-native-view-shot
In the previous implementation it was used like the following:
You have a QR image in your app and you want to send the image on social media so you wrap it in ViewShot:
<ViewShot ref="viewShot">
<QRImage
address={....}
image={...}
/>
</ViewShot>
Then when you click on the share image it does the following:
onQRImagePress = async (address: string) => {
const viewShotRef: any = this.refs.viewShot;
try {
const uri = await viewShotRef.capture();
const options: Options = {
url: "file://" + uri,
title: `address: ${address}`,
};
await Share.open(options);
}
catch (e) {
console.log(`Could not screenshot the QR or share it due to: ${e}`);
}
};
So we use the ref using the this.refs of the class.
I want to do it for a functional component. preferably using hooks.
I know that userRef exists but it didn't work for me. I also tried using createRef but wasn't sure how to implement it correctly.
for functional component you can use below hook
React alredy providing useRef hook so you can use it
import React, { useRef } from 'react';
import ViewShot from "react-native-view-shot";
const Mycomponent = () =>{
const viewShotRef = useRef();
// Access viewShotref
console.log(viewShotRef && viewShotRef.current)
return (
<View>
<ViewShot ref={viewShotRef} > {...children} </ViewShot>
</View>
)
}
import React, { useRef } from 'react';
import { TouchableOpacity, Text } from 'react-native';
import ViewShot from "react-native-view-shot";
class imageComponent = () => {
const viewShotRef = useRef();
const onSave = () => {
viewShotRef.current.capture().then(uri => {
console.log("do something with ", uri);
});
}
return (<>
<ViewShot ref={viewShotRef} options={{ format: "jpg", quality: 0.9 }}>
<Text>...Something to rasterize...</Text>
</ViewShot>
<TouchableOpacity onPress{onSave}>....</TouchableOpacity>
</>);
}

React Native save change switch with Async Storage

Im new in React Native, I have a problem with Switch, I want to save changes, dark mode and Switch, when I turn off the app and come back my changes should be saved. When I close the app, my switch came back to first position and dark mode does not work. I know that Im doing something wrong, but I did not mobile app and this is my first time and I dont know how to use AsyncStorage in this App to work this. Can somebody help me solve this problem?
import React, { createContext, useState, useEffect } from 'react';
import { AsyncStorage } from 'react-native';
export const DarkModeContext = createContext();
export default function DarkModeContextProvider(props) {
const [switchMode, setSwitchMode] = useState(false);
useEffect(() => {
let switch1 = switchMode;
AsyncStorage.setItem('switch1', JSON.stringify(switch1));
});
const SwitchThis = () => {
setSwitchMode(!switchMode);
};
return (
<DarkModeContext.Provider
value={{
switchMode,
SwitchThis
}}
>
{props.children}
</DarkModeContext.Provider>
);
}
and next component:
import React, { useState, useContext } from 'react';
import { View, ScrollView, TouchableOpacity, Text, AsyncStorage } from 'react-native';
import { List } from 'react-native-paper';
import BackgroundImage from './BackgroundImage';
import Clock from './Clock';
import TabIcon from './TabIcon';
import AddButton from './AddButton';
import { DarkModeContext } from './app-context';
const HomeScreen = () => {
const { switchMode } = useContext(DarkModeContext);
displayData = async () => {
try {
let switch1 = await AsyncStorage.getItem('switch1', function (err, switch1) {
JSON.parse(switch1)
}
)
return switch1
}
catch (error) {
return error
}
}
return (
<View
style={{
flex: 1,
backgroundColor: !switchMode ? 'white' : '#353535'
}}
>
<BackgroundImage fabButton={<AddButton/>}>
<Clock />
</BackgroundImage>
<ScrollView>
<List.Section>
<List.Subheader style={{ color: !switchMode ? 'black' : 'white' }}>
Task List
</List.Subheader>
<TouchableOpacity onPress={displayData}>
<Text>Click displayData</Text>
</TouchableOpacity>
</List.Section>
</ScrollView>
</View>
);
};
You are importing AsyncStorage from 'react-native' which is deprecated
use #react-native-community/react-native-async-storage
npm i #react-native-community/react-native-async-storage
And on your home screen you are not calling the function displayData() so how is data supposed to be displayed without function call.
and i do suggest making separate functions for writing and reading from async storage, it will help you reduce your code and time.
Like this:
let storeData=(name, obj)=> {
return new Promise((resolve,reject)=>{
let jsonOfItem = JSON.stringify(obj)
AsyncStorage.setItem(name, jsonOfItem).then(r=>resolve(jsonOfItem))
.catch(e=>reject(e))
})
}
let readData=(name)=> {
return new Promise((resolve,reject)=>{
//we want to wait for the Promise returned by AsyncStorage.setItem()
//to be resolved to the actual value before returning the value
AsyncStorage.getItem(name).then(r=> resolve(JSON.parse(r)) )
.catch(e=>reject(e))
})
}
//Now you can just read write easily in async function like this:
let fetchedData = await readData("key")
//and for storing data.
storeData("key",object)

Not able to use map function react-native

I am new to react native and I am using Async storage to store objects and then parse, by storing them in favorites array. I am trying to map each element in array and display it.
I get this error: this.state.favorites.map is not a function.
I think it's a state error but as I'm new to these concepts, i don't know how to fix it. Please help.
import React, {Component} from 'react';
import {StyleSheet, Text, View, Image, FlatList, Button, AsyncStorage,
TouchableOpacity} from 'react-native';
import ajax from './ajax.js';
import PropTypes from 'prop-types';
import InspirationList from './InspirationList';
import FavoriteItem from './FavoriteItem';
import ProductItem from './ProductItem';
class Favorites extends Component{
state = {
favorites:[],
};
componentDidMount(){
this.showProduct();
}
async showProduct() {
let k=0;
AsyncStorage.getAllKeys()
.then(keys => AsyncStorage.multiGet(keys)
.then((result) => {
result.map(req => req.forEach((element) => {
k++;
if(element!=null && k%2==0){
this.setState({favorites: JSON.parse(element) });
console.log(this.state.favorites.nume);
}
}));
}));
};
render(){
return(
<View style='styles.fav'>
{this.state.favorites.map((fav)=>
<Text>{fav.nume}</Text>
)}
</View>
);
}
}
const styles = StyleSheet.create({
fav:{
backgroundColor:'#999',
flex:1,
width:'100%',
paddingTop:150,
}
});
export default Favorites;
On your showProduct function you are overriding what your state originally was. When assigning the JSON.parse(element) you are changing your state instead of having an array your are converting it into an object, that's why you are getting that error. map exists only on array-like.
So maybe you can do something like:
async showProduct() {
let k=0;
AsyncStorage.getAllKeys()
.then(keys => AsyncStorage.multiGet(keys)
.then((result) => {
result.map(req => {
let result = [];
req.forEach((element) => {
k++;
if(element!=null && k%2==0){
result.push(JSON.parse(element))
}
});
this.setState({favorites: result });}
);
}));
};

Resources