React Native Can't find variable - react-native

I'm following along with a lab from school and this just doesn't match up with the results the teacher is getting. I keep getting "Render error Can't find variable sendMessageWithSMS". I'm trying to get it to set off an alert when I "send" an SMS.
I'm trying to call the function but it doesn't seem to know it's a function.
import React, { useState } from 'react';
import { Alert, StyleSheet, Text, View, Button, TextInput } from 'react-native';
import * as MailComposer from 'expo-mail-composer';
import * as SMS from 'expo-sms';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
function SMSScreen({navigation}) {
const [phoneNumber, setPhoneNumber] = useState();
const [message, setMessage] = useState();
const NumberInputHandler = (value) => {
setPhoneNumber(value);
}
const MessageInputHandler = (value) => {
setMessage(value);
}
sendMessageWithSMS = async () => {
const isAvailable = await SMS.isAvailableAsync();
if(isAvailable) {
const { result } = await SMS.sendSMSAsync(
[phoneNumber, '1231231234'],
message
);
console.log(result);
Alert.alert('Message Sent Successfully!')
} else {
Alert.alert('SMS Not Available')
}
}
return (
<View style={styles.container}>
<Text style={styles.label}>Send an Email</Text>
<TextInput style={styles.input} placeholder='Phone Number' onChangeText={NumberInputHandler} />
<TextInput style={styles.message} placeholder='Message' onChangeText={MessageInputHandler} />
<Button style={styles.button} title="Send Via SMS" onPress={sendMessageWithSMS} />
</View>
)
}

add const before function or this.functionname() write while using onPress

Related

React Native Async Storage - Cant render value on screen

Hey struggling with this one for a day now.
I am trying to store game data just the gameId and the Level for example Game 1 Level 12
Here is my screen
import React, { Component } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import { Text, StyleSheet, Button, View, ImageBackground, Pressable } from 'react- native';
import bg from "../assets/images/1.jpg";
import styles from '../assets/style';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const setScore = async (gameId, level) => {
//// SETS THE SCORE
try {
await AsyncStorage.setItem(scoreKey, level);
console.log(value)
} catch (error) {
console.log(error)
}
};
const getScore = async (gameId) => {
try {
let value = await AsyncStorage.getItem(JSON.stringify(gameId))
if(value !== null) {
// value previously stored
return JSON.stringify(value)
} else {
return "not started"
}
} catch(e) {
// error reading value
}
};
/// This would add game 1 and level 12
setScore('1','12') /// This part works
const theLevel = getScore(1)
export default function Home({navigation, route}) {
return (
<ImageBackground source={bg} resizeMode="cover" style={styles.imageBG}>
<View style={styles.GameList}>
<Text style={styles.mainTitle}>Current Level is {theLevel}</Text>
</View>
</ImageBackground>
);
}
At the bottom of the above code I want to display the level but I get the error
Error: Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}). If you meant to render a collection of children, use an array instead.
However If I alert(theLevel) it works fine can someone tell me what I am doing wrong please
Call getScore function from within useEffect hook of your Home component.
export default function Home({ navigation, route }) {
const [level, setLevel] = useState(0);
useEffect(() => {
async function getMyLevel() {
const lvl = await getScore(1);
setLevel(lvl);
}
getMyLevel();
}, []);
const onPress = async () => {
await setScore('1','12');
};
return (
<ImageBackground source={bg} resizeMode="cover" style={styles.imageBG}>
<View style={styles.GameList}>
<Text style={styles.mainTitle}>Current Level is {level}</Text>
</View>
<Button title="Set Score" onPress={onPress} />
</ImageBackground>
);
}

React Native Root Element, deciding on async call

I'm currently writing an App in React-Native, which also includes a login. I use AsyncStorage for saving the credentials. Now I want to show the user different Screens (Navigators) whether he is logged in or not.
To check if he is logged in, I check if there are credentials in the AsyncStorage, and the function to check this returns a promise. So now when I call the function in my component, it wont wait until the promise has resolved and I don't have any idea on how to solve. I tried with but this also failed. Maybe you have any idea. Below my code. Thanks
import 'react-native-gesture-handler'
import { NavigationContainer } from '#react-navigation/native'
import AppNavigation from './navigation/AppNavigation.js'
import { ThemeProvider, Text } from 'react-native-magnus'
import { useState, useEffect, useCallback, Suspense} from 'react'
import {React } from 'react'
import getNutrientsCompare from './utils/getNutrientsCompare.js'
import getLoginSession from './utils/getLoginSession.js'
import Login from './pages/Login.js'
import { ActivityIndicator } from 'react-native'
const wait = (timeout) => {
return new Promise(resolve => setTimeout(resolve, timeout));
}
const RootElement = () => {
const [result, setResult] = useState(null)
getLoginSession().then(data => {
[loginSessionState, setLoginSessionState] = useState("");
if (loginSessionState != null) {
setResult((
<ThemeProvider>
<NavigationContainer >
<AppNavigation />
</NavigationContainer>
</ThemeProvider>))
} else {
setResult((
<ThemeProvider>
<Login>
</Login>
</ThemeProvider>
))
}
})
return result
}
const App = () => {
return (
<Suspense fallback={<ActivityIndicator />}>
<RootElement />
</Suspense>
)
}
export default App
Give this a try
import { ActivityIndicator } from "react-native";
const RootElement = () => {
const [loggedIn, setLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
(async () => {
try {
const data = await getLoginSession();
if (data != null) {
setLoggedIn(true);
}
} catch (error) {
setLoggedIn(false);
}
setLoading(false);
})();
}, []);
return (
<>
{!loading ? (
loggedIn ? (
<ThemeProvider>
<NavigationContainer>
<AppNavigation />
</NavigationContainer>
</ThemeProvider>
) : (
<ThemeProvider>
<Login />
</ThemeProvider>
)
) : (
<ActivityIndicator size="large" color="#00ff00" />
)}
</>
);
};

How to use redux component in App.js React Native?

I'm doing a simple counter app. It has one label, and a button that you can increment by + 1 (each time it's pushed).
Using redux, I want to use the count that I store (in my Redux Store) in App.js file. However, I'm getting an error:
Error: could not find react-redux context value; please ensure the component is wrapped in a Provider
Using the useSelector works in other files, just not App.js. Is there a work around?
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Dogs from './components/Dogs';
import { Provider, useSelector } from 'react-redux';
import store from './redux/configureStore'
export default function App() {
const count = useSelector((state) => state.counter.count);
{/*useSelector does not work in this file!*/}
return (
<Provider store={store}>
<View style={styles.container}>
<Text>{`ha ${count}`}</Text>
<Dogs />
</View>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Counter.js
import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet, Button} from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { increment } from '../redux/ducks/counter'
const Counter = () => {
const count = useSelector((state) => state.counter.count);
{/*useSelector works in this file!*/}
const dispatch = useDispatch();
const handleIncrement = () => {
dispatch(increment())
};
return (
<div>
{/* <Text>{` COunt: ${count}`}</Text> */}
<Button onPress={handleIncrement}>Increment</Button>
</div>
);
}
const styles = StyleSheet.create({})
export default Counter;
redux/configureStore.js
import { combineReducers, createStore } from 'redux';
import counterReducer from './ducks/counter';
const reducer = combineReducers({
counter: counterReducer
});
const store = createStore(reducer);
export default store;
redux/ducks/counter.js
const INCREMENT = 'increment';
export const increment = () => ({
type: INCREMENT
})
const initialState = {
count: 0
};
export default ( state = initialState, action) => {
switch(action.type) {
case INCREMENT:
return{...state, count: state.count + 1}
default:
return state;
}
};
As error saying, you are using useSelector out side of provider. In your app.js you are using useSelector before the app renders, so it is not able to find store. So, create a component for functionality which you want to use in app.js like this :
Create a file, call it anything like CountView.js, in CountView.js use your redux login :
CountView.js
import React from 'react';
import { Text } from 'react-native';
import { useSelector } from 'react-redux';
const CountView = () => {
const count = useSelector((state) => state.counter.count);
return (
<Text>{`ha ${count}`}</Text>
)
}
export default CountView;
Now, In your app.js use this component :
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Dogs from './components/Dogs';
import { Provider } from 'react-redux';
import store from './redux/configureStore'
import CountView from '../components/CountView'; // import CountView component
export default function App() {
return (
<Provider store={store}>
<View style={styles.container}>
{/* Use component here */}
<CountView />
<Dogs />
</View>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Keep other things as it is, and now your functionality will works.
useSelector will work only if you wrap it inside Provider. you can create a wrapper file for App.
const AppWrapper = () => {
return (
<Provider store={store}> // Set context
<App /> // Now App has access to context
</Provider>
)
}
In App.js
const App = () => {
const count = useSelector((state) => state.counter.count); // will Work!
}
Unlike a regular React application, an expo React-Native application is not wrapped using an index.js file. Therefore when we wrap the provider in app.js for a React-Native app, we wrap it in index.js for React application. So the hooks like useSelector or useDispatch run before the provider is initialized. So, I would suggest not using any hooks in the app component, instead, we can create other components in the app.js and use the hooks in a separate component like in the code I have used below.
const Root = () => {
const [appIsReady, setAppIsReady] = useState(false);
const dispatch = useDispatch();
const fetchToken = async () => {
const token = await AsyncStorage.getItem("token");
console.log("Stored Token: ", token);
if (token) {
dispatch(setAuthLogin({ isAuthenticated: true, token }));
}
};
const LoadFonts = async () => {
await useFonts();
};
useEffect(() => {
async function prepare() {
try {
await SplashScreen.preventAutoHideAsync();
await LoadFonts();
await fetchToken();
} catch (e) {
console.warn(e);
} finally {
setAppIsReady(true);
}
}
prepare();
}, []);
const onLayoutRootView = useCallback(async () => {
if (appIsReady) {
await SplashScreen.hideAsync();
}
}, [appIsReady]);
if (!appIsReady) {
return null;
}
return (
<NavigationContainer onReady={onLayoutRootView}>
<MainNavigation />
</NavigationContainer>
);
};
export default function App() {
return (
<>
<Provider store={store}>
<ExpoStatusBar style="auto" />
<Root />
</Provider>
</>
);
}

useEffect returns unhandled promise

I have been for several hours trying to get an API to be called in ReactNative useEffect hook. Sometimes when I restart my app the value is resolved. But most of the time, I have an Unhandled promise rejection. I googled and tried various methods. I tried using .then etc.. I just can't figure it out.
import React, { useState, useContext, useEffect } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, FlatList } from 'react-native';
import { EvilIcons } from '#expo/vector-icons';
import jsonServer from '../api/jsonServer';
const ShowScreen = ({ navigation }) => {
const id = navigation.getParam('id');
const [post, setPost] = useState([]);
const getBlog = async () => {
const result = await jsonServer.get(`http://0.0.0.0/blog/docroot/jsonapi/node/article/${id}`);
return result;
}
useEffect(() => {
async function setToState() {
const val = await getBlog();
setPost(val);
}
setToState();
},[]);
return (
<View>
<Text>Here { console.log(post) }</Text>
</View>
);
};
ShowScreen.navigationOptions = ({ navigation }) => {
return {
headerRight: (
<TouchableOpacity
onPress={() =>
navigation.navigate('Edit', { id: navigation.getParam('id')
})}
>
<EvilIcons name="pencil" size={35} />
</TouchableOpacity>
)
};
};
const styles = StyleSheet.create({});
export default ShowScreen;
What you could do is something like this:
....
....
const [post, setPost] = useState([]);
const [isMounted, setIsMounted] = useState(false);
const getBlog = async () => {
const result = await jsonServer.get(`http://0.0.0.0/blog/docroot/jsonapi/node/article/${id}`);
return result;
}
useEffect(() => {
setIsMounted(true)
async function setToState() {
// using try catch I'm handling any type of rejection from promises. All errors will move to catch block.
try{
const val = await getBlog();
// checking if component is still mounted. If mounted then setting a value. We shouldn't update state on an unmounted component.
if(isMounted){
setPost(val);
}
} catch(err){
console.log("Error", err)
}
}
setToState();
return () => {
// Setting is mounted to false as the component is unmounted.
setIsMounted(false)
}
},[]);
I believe this will solve your Unhandled promise rejection error. Please try if it still doesn't solve the issue will create the same in Sanck.
I think my issue was not just promise, the issue is also seems to be me not handling undefined/null in the state. The below code is working for me.
import React, { useState, useContext, useEffect } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, FlatList } from 'react-native';
import { EvilIcons } from '#expo/vector-icons';
import jsonServer from '../api/jsonServer';
const ShowScreen = ({ navigation }) => {
const id = navigation.getParam('id');
const [post, setPost] = useState([]);
const getBlog = async () => {
const result = await jsonServer.get(`http://hello.com/jsonapi/node/article/${id}`).then(
res => {
setPost(res)
return res;
}, err => {
console.log(err);
});
}
useEffect(() => {
setPost(getBlog());
},[]);
return (
<View>
<Text>{ post.data ? post.data.data.id : "" }</Text>
</View>
);
};
export default ShowScreen;
Note: I am setting the state in useEffect as well as in the request. I am yet to check if I can just do it once.

Unable to load provider from react-redux module in react native

I am creating a slide bar, In that, I have used the react-redux library. When I call the class which contains the redux-code, it works fine. I want to show this slide bar after login. Therefore, with conditions (I set a state variable if user login successfully then only this page should get rendered), I tried to call the same file which shows a blank page. I printed the console log. I am able to print all the logs. But with conditions, I am not able to load the data.
I don't know much about react-redux.Can you assist me to resolve this?
My code is,
main.js,
import React, {Component} from 'react';
import {
StyleSheet,
Dimensions,
Platform,
View,
StatusBar,
DrawerLayoutAndroid,
} from 'react-native';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from '../Redux/reducers';
import { setNavigator, setActiveRoute } from "../Redux/actions";
import DrawerContent from '../Navigation/DrawerContent';
import Toolbar from '../Navigation/Toolbar';
import AppNavigation from '../Navigation/AppNavigation';
import { bgStatusBar, bgDrawer } from '../global.styles';
let store = createStore(reducer);
/* getDrawerWidth Default drawer width is screen width - header width
* https://material.io/guidelines/patterns/navigation-drawer.html
*/
const getDrawerWidth = () => Dimensions.get('window').width - (Platform.OS === 'android' ? 56 : 64);
export default class Main extends Component {
constructor() {
super();
this.drawer = React.createRef();
this.navigator = React.createRef();
}
componentDidMount() {
store.dispatch(setNavigator(this.navigator.current));
}
openDrawer = () => {
this.drawer.current.openDrawer();
};
closeDrawer = () => {
this.drawer.current.closeDrawer();
};
getActiveRouteName = navigationState => {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
};
render() {
return (
<Provider store={store}>
<DrawerLayoutAndroid
drawerWidth={getDrawerWidth()}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={
() => <DrawerContent closeDrawer={this.closeDrawer} />
}
ref={this.drawer}
>
<View style={styles.container}>
<StatusBar
translucent
animated
/>
<Toolbar showMenu={this.openDrawer} />
<AppNavigation
onNavigationStateChange={(prevState, currentState) => {
const currentScreen = this.getActiveRouteName(currentState);
store.dispatch(setActiveRoute(currentScreen));
}}
ref={this.navigator}
/>
</View>
</DrawerLayoutAndroid>
</Provider>
);
}
}
Login.js
import Main from './main';
render() {
return (
<View>
{this.state.isLoggedIn ?
<Main/>
:
<ChangePassword isUpdatePassword={this.state.isUpdatePassword} callLogin={this.callLogin}/>
);
}
}
If I just call Main class inside render method it works. But It does not work with conditions.