useState setmethod is updating inside useEffect but not reflecting the result outside - react-native

I was trying to use react-native-contacts library to display my contacts in the app. I am able to establish the connection and name of every person is visible when I do a console.log.
I have created this usestate hook
let [con,setContacts] = useState([])
What I want is to add all the names along with index to this array like this
{name:"adi",index:"1"}
I also did this inside a useEffect hook, but the issue is that when I call console.log(con.length) it prints the total value is 243.When I call the same method outside the useEffect it shows 1. It seems that the usestate is not updating outside.
CODE::
import React, {useState, useEffect} from 'react';
// Import all required component
import {
PermissionsAndroid,
Platform,
SafeAreaView,
StyleSheet,
Text,
View,
FlatList,
TextInput,
} from 'react-native';
import Contacts from 'react-native-contacts';
const ContactScreen = function(){
let [con, setContacts] = useState([]);
//console.log("after usestate")
useEffect(()=>{
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
{
'title': 'Contacts',
'message': 'This app would like to view your contacts.',
'buttonPositive': 'Please accept bare mortal'
}
)
Contacts.getAll().then(contacts => {
// contacts returned
console.log("heyyyyyy===================")
contacts.map((item,index)=>{
//console.log(item.displayName)
let nobj={name:item.displayName,index:index}
//console.log(nobj)
let arr=con.push(nobj)
//console.log(arr)
setContacts([arr])
console.log(con.length);
//console.log(con);
console.log("=================================================");
})
})
},[])
//issue ==>> displays 1
console.log(con.length);
return(
<View style={style.container}>
<Text>
this is contact screen
</Text>
<Text>{con.length}</Text>
</View>
)
}
const style = StyleSheet.create({
container: {
flex:1,
margin:10,
backgroundColor: '#ebebeb'
}
})
export default ContactScreen;
Output:
output shows that state is updating inside use effect

Hi Firstly you should map the contacts in your designed form. After that when it's mapped then just set the array of contacts in one line. Check out the my following solution.
import React, {useState, useEffect} from 'react';
// Import all required component
import {
PermissionsAndroid,
Platform,
SafeAreaView,
StyleSheet,
Text,
View,
FlatList,
TextInput,
} from 'react-native';
import Contacts from 'react-native-contacts';
const ContactScreen = function(){
let [con, setContacts] = useState([]);
//console.log("after usestate")
useEffect(()=>{
PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
{
'title': 'Contacts',
'message': 'This app would like to view your contacts.',
'buttonPositive': 'Please accept bare mortal'
}
)
Contacts.getAll().then(contacts => {
// contacts returned
const modififiedContacts = contacts.map((item,index)=>{
return {name:item.displayName,index:index}
});
setContacts(modifiedContacts);
})
},[])
//issue ==>> displays 1
console.log(con.length);
return(
<View style={style.container}>
<Text>
this is contact screen
</Text>
<Text>{con.length}</Text>
</View>
)
}
const style = StyleSheet.create({
container: {
flex:1,
margin:10,
backgroundColor: '#ebebeb'
}
})
export default ContactScreen;

Related

How to fix an Objects are not valid as a React child Error?

I am very new to programming with React-native, and I was wondering if anyone could explain how I should fix this error? I was following along with a tutorial and had an error come up due to this section of code, even though it matched the tutorial code.
Here is the section of code:
import React, { createContext, useContext } from "react";
import * as Google from "expo-google-app-auth";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const signInWithGoogle = async() => {
await Google.logInAsync
}
return (
<AuthContext.Provider
value={{
user: null,
}}
>
{children}
</AuthContext.Provider>
);
};
export default function useAuth() {
return useContext(AuthContext);
}
These other two sections may be relevant as well:
Root of the App:
import React from 'react';
import { Text, View, SafeAreaView, Button, Alert } from 'react-native';
import AuthProvider from "./hooks/useAuth";
import StackNavigator from "./StackNavigator";
import { NavigationContainer} from "#react-navigation/native";
// Function for creating button
export default function App() {
return (
<NavigationContainer>
<AuthProvider>
<StackNavigator />
</AuthProvider>
</NavigationContainer>
);
}
This is my code for the Login Screen:
import React from 'react';
import { View, Text } from 'react-native';
import useAuth from '../hooks/useAuth';
const LoginScreen = () => {
const { user } = useAuth();
console.log(user);
return (
<View>
<Text>
Login to the app
</Text>
</View>
);
};
export default LoginScreen
This is the error that appears:
Error: Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead.
I suggest you auth with firebase. it makes easier this things.

React native package #homee/react-native-mapbox-navigation not showing map (ANDROID)

I am trying to implement a turn by turn navigation in react native, I have used the package '#homee/react-native-mapbox-navigation'. I have used these instructions (https://reactnativeexample.com/smart-mapbox-turn-by-turn-routing-based-on-real-time-traffic-for-react-native/) to set all the gradle.properties / gradle.build and the manifest setting. This is how my app.js looks like:
import React from 'react';
import type {Node} from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import MapboxNavigation from '#homee/react-native-mapbox-navigation';
const App: () => Node = () => {
// const isDarkMode = useColorScheme() === 'dark';
// const backgroundStyle = {
// backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
// };
return (
<View style={styles.container}>
<MapboxNavigation
origin={[-97.760288, 30.273566]}
destination={[-97.918842, 30.494466]}
shouldSimulateRoute={true}
onLocationChange={(event) => {
const { latitude, longitude } = event.nativeEvent;
}}
onRouteProgressChange={(event) => {
const {
distanceTraveled,
durationRemaining,
fractionTraveled,
distanceRemaining,
} = event.nativeEvent;
}}
onError={(event) => {
const { message } = event.nativeEvent;
console.log('error', event)
}}
onCancelNavigation={() => {
// User tapped the "X" cancel button in the nav UI
// or canceled via the OS system tray on android.
// Do whatever you need to here.
}}
onArrive={() => {
// Called when you arrive at the destination.
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default App;
This is what my simulator is showing:
Is there someone who knows why I am getting an empty screen and how to fix this?
Thx guys!
The code works fine the mistake was that I put the meta-data tag in the wrong section
of the androidManifest.xml. I fixed this and it worked

Error in viewing item detail and TypeError: Cannot read property 'title' of undefined - Expo React Native

When trying to access the detail of the article, it prints the following error message, adding these lines of code:
13 | return (
14 | <View>
15 | <View>
> 16 | <Text>{article.title}</Text>
| ^ 17 | </View>
18 | </View>
19 | )
List of articles NewsListScreen.js
import React, { useEffect } from 'react';
import { StyleSheet, Text, View, FlatList } from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import * as NewsAction from '../redux/actions/NewsAction';
import Card from '../components/Card';
const NewsListScreen = props => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(NewsAction.fetchArticles())
}, [dispatch]);
const articles = useSelector(state => state.news.articles);
console.log(articles);
return (
<FlatList
data={articles}
keyExtractor={item => item.url}
renderItem={({item}) => (
<Card navigation={props.navigation}
title={item.title}
description={item.description}
image={item.urlToImage}
url={item.url}
/>
)}
/>
)
}
const styles = StyleSheet.create ({
});
export default NewsListScreen;
Print item detail NewsItemScreen.js
import React from 'react';
import { StyleSheet, Text, View, Platform, ImageBackground } from 'react-native';
import { useSelector } from 'react-redux';
const NewsItemScreen = props => {
const articleUrl = props.navigation.getParam('articleUrl');
//console.log(articleUrl);
const article = useSelector(state => state.news.articles.find(article => article.url === articleUrl));
//console.log(article);
return (
<View>
<View>
<Text>{article.title}</Text>
</View>
</View>
)
}
const styles = StyleSheet.create ({
});
export default NewsItemScreen;
When I replace this <Text>{article.title}</Text> with <Text>Hello!</Text> it shows the screen printing Hello! with no error.
These articles are the ones that are listed and the ones that are shown in the console correctly, the same ones that I try to see the complete detail, but I get the error message already mentioned.
author: "Megan Rose Dickey"
content: "Hellllooooo, 2021! Welcome back to Human Capital, a weekly newsletter that details the latest in the realms of labor, and diversity and inclusion.
↵Not a ton happened this week so I figured Id use th… [+6204 chars]"
description: "Hellllooooo, 2021! Welcome back to Human Capital, a weekly newsletter that details the latest in the realms of labor, and diversity and inclusion. Not a ton happened this week so I figured I’d use the time to look back on some of the more notable labor storie…"
publishedAt: "2021-01-02T20:00:52Z"
source:
id: "techcrunch"
name: "TechCrunch"
__proto__: Object
title: "Human Capital: The biggest labor stories of 2020"
url: "https://techcrunch.com/2021/01/02/human-capital-the-biggest-labor-stories-of-2020/"
urlToImage: "https://techcrunch.com/wp-content/uploads/2020/08/GettyImages-1142216084.jpg?w=601"
Code Proyect: https://github.com/Publisere/app-news-react
Note: It should be noted that the data does exist, it is not empty data.
Ok well...it seems that article is not defined 😂.
The first time this component is rendered, Article is undefined so you just need to wait (or display a loader, empty page, I let you manage that) before rendering article data.
import React from 'react';
import { StyleSheet, Text, View, Platform, ImageBackground } from 'react-native';
import { useSelector } from 'react-redux';
const NewsItemScreen = props => {
const articleUrl = props.navigation.getParam('articleUrl');
const article = useSelector(state => state.news.articles.find(article => article.url === articleUrl));
if (!article) return null;
return (
<View>
<View>
<Text>{article.title}</Text>
</View>
</View>
)
}
const styles = StyleSheet.create ({
});
export default NewsItemScreen;

Getting Error: The component for route 'Books' must be a React component. For example: import MyScreen from './MyScreen';

Getting the following error:
The component for route 'Books' must be a React component. For example:
import MyScreen from './MyScreen';
But i'm not even using react-navigation in this screen.
https://snack.expo.io/#ganiyat1/colorful-thrills
import React, { useState } from 'react';
import { StyleSheet, SafeAreaView } from 'react-native';
import MaterialTabs from 'react-native-material-tabs';
const Book = () => {
const [selectedTab, setSelectedTab] = useState(0);
return (
<SafeAreaView style={styles.container}>
<MaterialTabs
items={['New Releases', 'All', 'BOM']}
selectedIndex={selectedTab}
onChange={setSelectedTab}
barColor="#1fbcd2"
indicatorColor="#ff914d"
activeTextColor="white"
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
You are not exporting the Book component.
In the book component, either add export default Book to the bottom, or do export const Book.... You also need to change the import to for a default export
import Book from './components/Books';
or
import { Book } from './components/Books';
if you do a named export (export const Book).

React call function and setstate when go back to a previous screen

I'm new in React's world
I have 2 screens : Stock and Barcode.
In Stock, i navigate to Barcode's screen.
When i scan a barcode, i go back to the previous screen I would like to set the input text with the barcode and call a function. In my example joinData();
The problem is to set the input text and call a function.
I tried examples and answers but i don't find or don't understand how to to that.
I tried something in componentDidUpdate() but it fails
Invariant Violation:Maximum update depth exceeded
Stock.js
import React, {useState} from "react";
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
//galio
import { Block, Text, theme } from "galio-framework";
import { Button, Icon, Input } from "../components/";
export default class Stock extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.array = [];
this.state = {
arrayHolder: [],
Input_ITMREF: ''
};
}
// I tried this but it fails
componentDidUpdate() {
if (this.props.navigation.getParam('itmref') != 'undefined') {
this.setState({ Input_ITMREF: this.props.navigation.getParam('itmref')});
}
}
componentDidMount() {
this.setState({ arrayHolder: [...this.array] }) // Rafraîchit la liste
}
joinData = () => {
vxml = this.state.Input_ITMREF+" I do something";
}
Render() {
return (
<Block flex>
<Block row space="evenly">
<Block center>
<Input
placeholder='Code article'
onChangeText={data => this.setState({ Input_ITMREF: data })}
ref={this.myRef}
/>
</Block>
</Block>
<Block center>
<Button style={styles.button} onPress={() => this.props.navigation.navigate('Barcode')}>Barcode</Button>
<Text style={{ margin: 10 }}>Post: {this.props.navigation.getParam('itmref')}</Text>
</Block>
</Block>
);
}
}
And Barcode.js
import React, {} from 'react';
import { ScrollView, TouchableWithoutFeedback, Dimensions, StyleSheet, FlatList, View, Alert, TouchableOpacity, TextInput } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import { Button } from "../components/";
export default class Barcode extends React.Component {
static navigationOptions = {
header: null //hide the header bar
};
handleBarCodeScanned = ({ type, data }) => {
this.props.navigation.navigate("Stock", {
itmref: data
});
};
render() {
return (
<BarCodeScanner
onBarCodeScanned={this.handleBarCodeScanned}
style={styles.barcodeScanner}
/>
);
}
}
You can pass a state handler function as prop to Barcode screen and use that to set value for textInput in state.
in Stock(in state)
state = {
inputValue: ''
}
....
const setInputTextValue= (newValue) => {
this.setState({
inputValue: newValue
})
you pass this function as prop to Barcode scene and call it whenever you wanna set a new value(considering Stock scene is still mounted).
UPDATE: What is the proper way to update a previous StackNavigator screen?
also another solution i just saw: Updating State of Another Screen in React Navigation
You need to use WillFocus method(Included in react-navigation) when you comeback from Barcodepage to stockPage
componentDidMount(){
console.log("willFocus runs") initial start
const {navigation} = this.props;
navigation.addListener ('willFocus', async () =>{
console.log("willFocus runs") // calling it here to make sure it is logged at every time screen is focused after initial start
});
}
For More Information read this document
https://reactnavigation.org/docs/function-after-focusing-screen/