React native each key should have a unique - react-native

Why I get this error Message?
Warning: Each child in a list should have a unique "key" prop.
import * as React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Image, Dimensions, Animated, FlatList } from 'react-native';
const StoryProfile = () => {
const dataStory = [
{
type: 'NORMAL',
item: {
id: '1',
image: 'https://picsum.photos/200',
}
},
{
type: 'NORMAL',
item: {
id: '2',
image: 'https://picsum.photos/200',
}
},
{
type: 'NORMAL',
item: {
id: '3',
image: 'https://picsum.photos/200',
}
},
{
type: 'NORMAL',
item: {
id: '4',
image: 'https://picsum.photos/200',
}
},
{
type: 'NORMAL',
item: {
id: '5',
image: 'https://picsum.photos/200',
}
},
{
type: 'NORMAL',
item: {
id: '6',
image: 'https://picsum.photos/200',
}
},
];
const Item = React.memo(({ image }) => {
return (
<View>
<Image source={{uri: image}} height={48} width={48} resizeMode="contain" />
</View>
)
});
const renderItem = ({ item }) => {
return (
<Item image={item.image} />
)
};
return (
<View style={styles.container}>
<FlatList
data={dataStory}
keyExtractor={item => item.id}
key={Math.random(1000)}
renderItem={renderItem}
/>
</View>
)
};
const styles = StyleSheet.create({
container: {
flex: 1
}
})
export default StoryProfile;
I have tried a key prop but thats not working. What I am doing wrong ?
........................................................................................................................................................................................................................

No need to have a key prop on a FlatList component:
<FlatList
data={dataStory}
keyExtractor={item => item.id}
key={Math.random(1000)} {/* No need to have a key attribute on FlatList */}
renderItem={renderItem}
/>
When you add a keyExtractor={item => item.id}, it will search the id on each object of your dataStory, which is undefined in your case, so the key in your case is the same undefined.
So, the first solution is:
Instead of having:
{
type: 'NORMAL',
item: {
id: '1',
image: 'https://picsum.photos/200',
}
}
You should have this:
{
id: '1',
type: 'NORMAL',
item: {
image: 'https://picsum.photos/200',
}
}
The second solution is to change the keyExtractor to be:
keyExtractor={item => item.item.id}
or:
keyExtractor={({item}) => item.id}

Related

How to maintain the scroll position when switching from vertical to horizontal orientation in Flatlist?

How can I maintain the scroll position when I switch from vertical to horizontal orientation in the flat list? A change of the horizontal prop resets the scroll position.
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
horizontal={isHorizontal} // change triggers reset to first item
/>
Flatlist has a method called scrollToIndex that is able to scroll to the specific item. You can leverage this to return to the correct scroll position by saving the index of the item that is in view in a useState and then passing the state to the scrollToIndex function whenever ishorizontal state is changed. I've created a basic example below.
import React, { useEffect, useState, useRef } from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, Dimensions } from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d73',
title: 'forth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d74',
title: 'fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d71',
title: 'sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29dfs',
title: 'seven Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29ddd',
title: 'eight Item',
},
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const [isHorizontal, setIsHorizontal] = useState(false)
const [index, setIndex] = useState(0)
const flatListRef = useRef(null)
const renderItem = ({ item }) => (
<Item title={item.title} />
);
useEffect(() => {
const subscription = Dimensions.addEventListener(
"change",
({ window: { width, height } }) => {
if (width < height) {
setIsHorizontal(true)
} else {
setIsHorizontal(false)
}
}
);
return () => subscription?.remove();
});
useEffect(() => {
if(flatListRef.current) {
console.log(index);
flatListRef.current?.scrollToIndex({index: index})
}
}, [isHorizontal]);
const onViewRef = React.useRef((viewableItems) => {
setIndex(viewableItems.viewableItems[1].index);
});
return (
<SafeAreaView style={styles.container}>
<FlatList
initialScrollIndex={index}
ref={flatListRef}
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
onViewableItemsChanged={onViewRef.current}
isHorizontal={isHorizontal}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
margin:100
},
title: {
fontSize: 32,
},
});
export default App;

Why isn't my FlatList showing in React Native?

I am following a tutorial but as I code along I am stuck,
Why isn't my FlatList not showing?
App.js is simply returning MessagesScreen "screen".
This is my code for a MessagesScreen:
import React from "react";
import { FlatList } from "react-native";
import ListItem from "../components/ListItem";
const messages = [
{
id: 1,
title: "T1",
description: "D1",
image: require("../assets/mosh.jpg"),
},
{
id: 2,
title: "T2",
description: "D2",
image: require("../assets/mosh.jpg"),
},
{
id: 3,
title: "T3",
description: "D3",
image: require("../assets/mosh.jpg"),
},
{
id: 4,
title: "T4",
description: "D4",
image: require("../assets/mosh.jpg"),
},
];
const MessagesScreen = () => {
return (
<FlatList>
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem=
{({ item }) => {
return (
<ListItem
title={item.title}
subTitle={item.subTitle}
image={item.image}
/>
);
}}
</FlatList>
);
};
export default MessagesScreen;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my component for the ListItem:
import React from "react";
import { View, StyleSheet, Image } from "react-native";
import AppText from "./AppText";
import colors from "../config/colors";
function ListItem({ title, subTitle, image }) {
return (
<View style={styles.container}>
<Image style={styles.image} source={image} />
<View>
<AppText style={styles.title}>{title}</AppText>
<AppText style={styles.subTitle}>{subTitle}</AppText>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
},
image: {
width: 70,
height: 70,
borderRadius: 35,
marginRight: 10,
},
subTitle: {
color: colors.medium,
},
title: {
fontWeight: "500",
},
});
export default ListItem;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
What I've tried is to use the return inside the "renderItem", but with no work, also done it without. The code doesn't give me any errors, so I can't see where the problem is.
You're accessing a property that doesn't exist on your items: subTitle. Did you mean to use description?
Also, I don't believe you can pass in the result of a require call like that. Try passing the raw url and placing the require in the image={} prop instead
Oh it's just a quick fix.
FlatList should be one tag:
const MessagesScreen = () => {
return (
<FlatList // <--- edit here
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem=
{({ item }) => {
return (
<ListItem
title={item.title}
subTitle={item.subTitle}
image={item.image}
/>
);
}}
/> // <--- and here
);
};
Here's a codesandbox to demonstrate

How to display list of countries as webpage in expo react native

I am beginner with react native expo, just creating my first project. I am able to make a flat list and app is working great so far.
However now I need to make something like this,
As being newbie, I am not sure where to start, It seems like a webview is used but I am not sure how to put flatview into webview, or am I completely on wrong track ?
This is what I coded so far,
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});
export default App;
Result:
Code:
import React from "react";
import { FlatList, SafeAreaView, StyleSheet, Text, View } from "react-native";
class App extends React.Component {
state = {
data: [
{ id: "00", name: "Mazda RX-7" },
{ id: "01", name: "McLaren F1" },
{ id: "02", name: "Mini Cooper" },
{ id: "03", name: "BMW 645 Ci" }
]
};
render() {
const columns = 3;
return (
<SafeAreaView>
<FlatList
data={createRows(this.state.data, columns)}
keyExtractor={item => item.id}
numColumns={columns}
renderItem={({ item }) => {
if (item.empty) {
return <View style={[styles.item, styles.itemEmpty]} />;
}
return (
<View style={styles.item}>
<Text style={styles.text}>{item.name}</Text>
</View>
);
}}
/>
</SafeAreaView>
);
}
}
function createRows(data, columns) {
const rows = Math.floor(data.length / columns);
let lastRowElements = data.length - rows * columns;
while (lastRowElements !== columns) {
data.push({
id: `empty-${lastRowElements}`,
name: `empty-${lastRowElements}`,
empty: true
});
lastRowElements += 1;
}
return data;
}
const styles = StyleSheet.create({
item: {
alignItems: "center",
backgroundColor: "#dcda48",
flexBasis: 0,
flexGrow: 1,
margin: 4,
padding: 20
},
itemEmpty: {
backgroundColor: "transparent"
},
text: {
color: "#333333"
}
});
export default App;

How to create a multi-select on React-Native-Super-Grid

I am new in React Native and I have been trying to implement a multi-select on a Flatlist. I recently found the react-native-super-grid component and I have been trying to customize it so I maybe able to do a multi-select and no luck thus far.
Am I on the right track, or is there a component that does a grid and multi-select?
Thank you, :'(
import React, { Component } from 'react'
import { View, StyleSheet, Text } from 'react-native'
import { FlatGrid } from 'react-native-super-grid'
export default class GridFlatlist extends Component {
render() {
const items = [
{ name: 'Pick n Pay', code: '#1abc9c' }, { name: 'EMERALD', code: '#2ecc71' },
{ name: 'PETER RIVER', code: '#3498db' }, { name: 'AMETHYST', code: '#9b59b6' },
{ name: 'WET ASPHALT', code: '#34495e' }, { name: 'GREEN SEA', code: '#16a085' },
{ name: 'NEPHRITIS', code: '#27ae60' }, { name: 'BELIZE HOLE', code: '#2980b9' },
{ name: 'WISTERIA', code: '#8e44ad' }, { name: 'MIDNIGHT BLUE', code: '#2c3e50' },
{ name: 'SUN FLOWER', code: '#f1c40f' }, { name: 'CARROT', code: '#e67e22' },
{ name: 'ALIZARIN', code: '#e74c3c' }, { name: 'CLOUDS', code: '#ecf0f1' },
{ name: 'CONCRETE', code: '#95a5a6' }, { name: 'ORANGE', code: '#f39c12' },
{ name: 'PUMPKIN', code: '#d35400' }, { name: 'POMEGRANATE', code: '#c0392b' },
{ name: 'SILVER', code: '#bdc3c7' },
];
return (
<FlatGrid
itemDimension={110}
items={items}
style={styles.gridView}
renderItem={({ item, index }) => (
<View style={[styles.itemContainer, { backgroundColor: item.code }]}>
<Text style={styles.itemName}>{item.name}</Text>
<Text style={styles.itemCode}>{item.code}</Text>
</View>
)} />
)
}
}
const styles = StyleSheet.create({
gridView: {
marginTop: 20,
flex: 1,
},
itemContainer: {
justifyContent: 'flex-end',
padding: 10,
height: 110,
},
itemName: {
fontSize: 16,
color: '#fff',
fontWeight: '600',
},
itemCode: {
fontWeight: '600',
fontSize: 12,
color: '#fff',
},
})
You can use a flatlist to create a multi select very simply. Only thing is react native doesnt have a checkbox that works in both Android and IOS. The below example is for Android and you can use the Checkbox from react native elements to support both platforms.
Here's the code for the solution.
const CheckList = props => {
const [data, setData] = useState([]);
useEffect(() => {
setData(props.data);
}, []);
const OnCheckChange = id => {
const arr = [...data];
const item = arr.find(item => item.id === id);
item.isChecked = !item.isChecked;
setData(arr);
// can use a callback to update parent from here
};
return (
<FlatList
data={data}
renderItem={({ item }) => {
return (
<View style={{ flexDirection: "row" }}>
<CheckBox
value={item.isChecked}
onValueChange={() => OnCheckChange(item.id)}
/>
<Text>{item.name}</Text>
</View>
);
}}
/>
);
};
const items = [
{ id: 1, name: "Pick n Pay", code: "#1abc9c" },
{ id: 2, name: "EMERALD", code: "#2ecc71" },
{ id: 3, name: "PETER RIVER", code: "#3498db" },
{ id: 4, name: "AMETHYST", code: "#9b59b6" },
{ id: 5, name: "WET ASPHALT", code: "#34495e" },
{ id: 6, name: "GREEN SEA", code: "#16a085" },
{ id: 7, name: "NEPHRITIS", code: "#27ae60" },
{ id: 8, name: "BELIZE HOLE", code: "#2980b9" }
];
class App extends Component {
render() {
return (
<View style={styles.app}>
<CheckList data={items} />
<Button onPress={() => {}} title="Example button" />
</View>
);
}
}

How to use React Hooks with react-native-tab-view

red error screen 1
Cannot read property 'configureProps' of undefined
I was using the react-tab-view with react Hooks and typescript but I have some issues somebody could give me a hand...
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Dimensions } from 'reactnative';
import { TabView, SceneMap } from 'react-native-tab-view';
const FirstRoute = () => (
<View style={[styles.scene, { backgroundColor: '#ff4081' }]} />
);
const SecondRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
interface Props {
navigation: any;
}
export default function Home(props: Props) {
const [rar, setRar] = useState({
index: 0,
routes: [
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]
});
var NativeAppEventEmitter = require('RCTNativeAppEventEmitter');
return (
<View>
<TouchableOpacity onPress={props.navigation.openDrawer}>
<Text>hola desde home</Text>
</TouchableOpacity>
<TabView
navigationState={rar}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
})}
onIndexChange={index => ({ index })}
initialLayout={{ width: Dimensions.get('window').width, height: 250 }}
/>
</View>
)
}
const styles = StyleSheet.create({
scene: {
flex: 0.3,
},
});
change
onIndexChange={index => ({ index })}
to
onIndexChange={index => setRar({ ...rar, index })}
that should fix the error you are facing
import React, { useState, useEffect } from 'react';
import { Container } from './styles';
import { View, StyleSheet, Dimensions } from 'react-native';
import { TabView, SceneMap } from 'react-native-tab-view';
const LatestRoute = () => (
<View style={[styles.scene, { backgroundColor: '#ff4081' }]} />
);
const FavoritesRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
const AllRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
const styles = StyleSheet.create({
scene: {
flex: 1,
},
});
export default function Main() {
const initialState = {
index: 0,
routes: [
{ key: 'latest', title: 'Latest' },
{ key: 'favorites', title: 'Favorites' },
{ key: 'all', title: 'All' },
],
};
const [ state, setState ] = useState(initialState);
function selectTab ( index ) {
this.initialState = {
index: index,
routes: [
{ key: 'latest', title: 'Latest' },
{ key: 'favorites', title: 'Favorites' },
{ key: 'all', title: 'All' },
],
};
return setState(this.initialState);
}
return (
<Container>
<TabView
navigationState={state}
renderScene={SceneMap({ latest: LatestRoute, favorites: FavoritesRoute, all: AllRoute })}
onIndexChange={ (index) => selectTab(index) }
initialLayout={{ width: Dimensions.get('window').width, height : Dimensions.get('window').height }}
/>
</Container>
);
}