Nested Lists using FlatList or SectionList - react-native

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.

Related

Why does my list of Realm objects loaded into FlatList using realm-react only render if I use the spread operator?

import React from "react"
import { initialWindowMetrics, SafeAreaProvider } from "react-native-safe-area-context"
import {FlatList, SafeAreaView, Text, View, } from "react-native";
import {colors} from "./theme";
import {LocationRealm} from "./realm/models/LocationRealm";
import RealmContext from './realm/AppRealm';
const { RealmProvider, useQuery } = RealmContext;
function App() {
return <RealmProvider>
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
<LocationsView/>
</SafeAreaProvider>
</RealmProvider>
}
export const LocationsView = () => {
const locations = useQuery(LocationRealm)
return (
<SafeAreaView style={{flex: 1, height: "100%"}}>
<FlatList
data={[...locations]} // <--- working (shows on UI)
// data={locations} // <-- not working (empty list)
keyExtractor={ (item, index) => `${item.id}` }
renderItem={({item}) => {
{console.log(item)}
return <View style={{height: 100, backgroundColor: colors.tint}}>
<Text>{item.locationName}</Text>
</View>
}}
/>
</SafeAreaView>
)
}
export default App
import Realm from "realm";
export class LocationRealm extends Realm.Object<LocationRealm> {
id!: string;
locationName!: string;
static generate(index: number, name: String) {
return {
id: `${Math.random()}`,
locationName: name,
}
}
static schema: Realm.ObjectSchema = {
name: "LocationRealm",
primaryKey: "id",
properties: {
id: "string",
locationName: "string",
}
}
}
The above code is only rendering LocationRealm objects into the UI from the Realm Database when using [...locations] instead of just locations. In all the demos and example projects I have seen, the spread operator was not needed. I am not getting any error messages or crashes, just an empty FlatList.
"#realm/react": "^0.4.3"
"realm": "^11.4.0"
I'm having the same issue here, ignore that chump above.
Strangely - if you use locations.map() you'll be able to render using the same data set, but FlatList returns an empty UI.
If you use the underlying VirtualizedList component and pass data={locations} you'll also be able to render.
There must be something with the FlatList component itself that's having issues with the realm results from useQuery.
https://github.com/realm/realm-js/issues/5404
The issue is that FlatList from react-native introduced a guard in the _getItemCount function in RN 0.71.2. Here is the commit:
https://github.com/facebook/react-native/commit/d574ea3526e713eae2c6e20c7a68fa66ff4ad7d2
useQuery returns an object of type Realm.Results, which fails the Array.isArray() guard.
You can use patch-package to remove the guard from the FlatList.

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.

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;

NativeBase: Button does not work, but ReactNative's Button does

Experiencing a strange issue in my React Native project for Android.
Using React-Navigation, I have a component with a button inside. This button should navigate to a new screen.
Thing is, the built-in button of React Native works like a charm, while the button of Native Base does not. I am completely confused, even more because I use this Native Base Button in another location, too. And there it works fine.
What is going on here?
Here, you see the application works with the built-in React Native button:
On the opposite, using the button of Native Base, it not only does not work, even styles are not applied.
Here is the code with the React Native button:
import React from "react";
import { Button, View, Text, StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
type Props = { navigation: any };
const ButtonTestScreen: React.FC<Props> = ({ navigation }) => {
return (
<View>
<Button
title="Hi i am a button"
onPress={() => navigation.navigate("Details")}
></Button>
</View>
);
};
export default withNavigation(ButtonTestScreen);
And the code with Native Base button:
import React from "react";
import { Button, View, Text, StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
import ButtonNavigate from "../../components/atoms/ButtonNavigate/ButtonNavigate";
type Props = { navigation: any };
const ButtonTestScreen: React.FC<Props> = ({ navigation }) => {
return (
<View>
<ButtonNavigate
title="Hi i am a button"
navigateTo="Details"
></ButtonNavigate>
</View>
);
};
const styles = StyleSheet.create({
button_style: {
backgroundColor: "red"
},
text_style: {
color: "#000",
fontSize: 30
}
});
export default withNavigation(ButtonTestScreen);
And the respective ButtonNavigate component itself:
import React from "react";
import { StyleSheet } from "react-native";
import { withNavigation } from "react-navigation";
import { Button, Text } from "native-base";
type Props = {
title: string,
navigateTo: string,
navigation: any
};
const ButtonNavigate: React.FC<Props> = ({ title, navigateTo, navigation }) => {
return (
<Button
rounded
transparent
style={styles.button_style}
onPress={() => navigation.navigate(navigateTo)}
>
<Text style={styles.text_style}>{title}</Text>
</Button>
);
};
const styles = StyleSheet.create({
button_style: {
backgroundColor: "red"
},
text_style: {
color: "#151414"
}
});
export default withNavigation(ButtonNavigate);
I have just tested you code in expo.snack but without navigation and its ok,
see it here
You can test in your app to remove navigation and go step by step until you find the bug.
Folks, reason for this strange behavior is the "rounded" property of Native Base's button. In my application, somehow it causes the button to become non-clickable.
Maybe contributors of Native Base know what to do with this problem, so if you read this, maybe you have an idea.
Solution for my now was simply removing "rounded".
Native Base: 2.13.8
React-Navigation: 4.0.10
In my case it was the "top" in the container property of the button causing this issue. Removed it and adding "marginBottom" to the container above it solved the issue

React-Native, ActionSheetIOS display instead of Picker

I would like to use the ActionSheetIOS on iOS, instead of the native picker wheel.
My app crashes out, how can I display my component?
Here is my Picker component:
// Picker.ios.js
import React, { Component } from "react";
import { StyleSheet, ActionSheetIOS, View } from "react-native";
const PickerList = props => {
const { label, options, selectedValue, name, onChange, identifier } = props;
return ActionSheetIOS.showActionSheetWithOptions(
{
options: options,
cancelButtonIndex: 1,
destructiveButtonIndex: 2
},
optionIndex => {
console.log('clicked')
}
);
};
export default PickerList;
I'm using conditional rendering to display my pickers, and a platform specific import:
import Picker from "./common/Picker";
{setYear
? <Picker
selectedValue={setGroup}
label="Year group"
onChange={this.onGroupChange}
options={
categories.find(category => {
return category.id == setYear;
}).options
}
/>
: null}
ActionSheetIOS only shows the options, you have to have some view component to replace the picker in the view. I used TouchableOpacity ja ActionSheetIOS to replace Picker on IOS like this:
<TouchableOpacity onPress={this.onSelectCategory.bind(this)}>
<Text style={styles.textInputStyle}>
{this.state.category}
</Text>
</TouchableOpacity>
onSelectCategory() {
ActionSheetIOS.showActionSheetWithOptions(
{ options: FEEDBACK_CATEGORIES},
(buttonIndex) => this.setState({ category: FEEDBACK_CATEGORIES[buttonIndex] }));
}
I use this.state.category to show my selection in TouchableOpacity
When user press the TouchableOpacity the ActionSheetIOS is shown
When user select option the callback function is called and I update the
selected index to the this.state.category