Error in viewing item detail and TypeError: Cannot read property 'title' of undefined - Expo React Native - 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;

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.

Nested Lists using FlatList or SectionList

Heres my problem. I need to use react navigator to enter a new page with the appropriate data from a FLatList or SectionList using route.params.
Normally that would be no problem for me, but I want a more complex list with new lists in the list (Ideally using json in the future). I want to make a List that displays and sort animals into categories in a listed format. When you touch the desired animal you're forwarded to a page displaying info and facts aboat that animal.
The list of data looks like this (its shortend, but this is the template):
const species= [
{
title: 'SpeciesGroup1',
data: [
{
id: 1,
title: 'Species1',
}
],
},
{
title: 'SpeciesGroup2',
data: [
{
id: 1,
title: 'Species2',
}
],
},
];
This is the screen that diplays the data. AppList is a FlatList component. Everything is displayed as I want it. I've also tried using SectionList and that worked too.
import React from 'react';
import {
StyleSheet,
View,
FlatList,
} from 'react-native';
import AppList from '../components/AppList';
import AppText from '../components/AppText';
import Screen from '../components/Screen';
import routes from '../navigation/routes';
function SpeciesListScreen({ navigation }) {
return (
<Screen>
<FlatList
data={ species }
renderItem={({ item }) => (
<View style={ styles.container }>
<AppText textType='header'>{ item.title }</AppText>
<AppList items={item.data} onPress={ () => navigation.navigate( routes.SPECIES, item.data )} numberOfColumns={ 2 } />
</View>
)}
/>
</Screen>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
}
});
export default SpeciesListScreen;
Until now eveything works and loads as it should. The problem comes when i want to display the information in the SpeciesScreen. For some reason I can't access the info in the data array, in this case "title". The page loads perfectly fine. Just without the data.
The screen showing the species info looks like this:
import React from 'react';
import {
StyleSheet,
View,
FlatList,
} from 'react-native';
import AppText from '../components/AppText';
import Screen from '../components/Screen';
function SpeciesScreen({ route }) {
const animal = route.params;
return (
<Screen>
<AppText textType='header'>{ animal.title }</AppText>
</Screen>
);
}
export default SpeciesScreen;
Does anyone have any tips or solutions?
The way you pass the route params is incorrect. The route params are supposed to be an object, but item.data is an array.
You can correct this as follows.
<AppList items={item.data} onPress={ () => navigation.navigate( routes.SPECIES, { species: item.data} )} numberOfColumns={ 2 } />
You can access them as follows.
const animal = route.params.species[0]
If you know that this will always be just one object, you could do this as a preprocessing and just pass the object to the route params. If you got multiple objects, then you might want to loop over it.

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

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;

React Native GraphQL nested data array returning error

I have tried everything I can think of to solve this and am still stumped. I am using AWS AppSync GraphQL to store a dataset that I would like to call into a SectionList.
For the SectionList I am using a hardcoded id to call the data set through a GraphQL query. The SectionList displays correctly when I am using dummy data. It also displays the 1-to-1 relationships in the API correctly.
I already configured amplify to increase the statement depth and I can see the data in the Object.
Code for the SectionList
import React, { useState, useEffect } from 'react';
import { View, StyleSheet, Text, Image, ImageBackground, ScrollView, TouchableOpacity, SectionList, SafeAreaView } from 'react-native';
import Feather from 'react-native-vector-icons/Feather';
import AntDesign from 'react-native-vector-icons/AntDesign';
import { API, graphqlOperation } from 'aws-amplify';
import { getGame, listGameSections, listGames } from '../graphql/queries';
const Item = ({ title }) => (
<View>
<Text>
{title}
</Text>
</View>
);
const GameScreen = ({ navigation }) => {
const [game, setGame] = useState([]);
useEffect(() => {
const fetchGame = async () => {
const gameInfo = { id: '0e2cb273-b535-4cf7-ab16-198c44a4991c'};
if (!gameInfo) {
return;
}
try {
const response = await API.graphql(graphqlOperation(getGame, {id: gameInfo.id}))
setGame(response.data.getGame);
console.log(response);
} catch (e) {
}
};
fetchGame();
}, [])
return (
<SafeAreaView>
<View>
<Text>
{game.name}
</Text>
</View>
<SectionList
sections={game.sections.items}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<View>
<Text>{title}</Text>
</View>
)}>
</SafeAreaView>
)
};
export default GameScreen;
Log of the object.
I am attempting to display the getGame.sections.items array but am returning an error undefined is not an object. Cannot read property items of undefined.
Please help, I am so stumped now. When I call game.name earlier in the function it displays correctly, but game.sections.items throws an error in the SectionList that it is undefined.
Xadm, you pointed me in the right direction. I added this to my code:
const [game, setGame] = useState({});
const [gameSection, setGameSection] = useState([]);
and in my useEffect:
setGameSection(response.data.getGame.sections.items)
When calling the data, game.name wanted an object, while game.sections.items wanted an array for the SectionList. Adding 2 different functions for each initial states, one for the objects and one for the array, was able to fix the problem and render the data.

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/