I'm looking for rearrange Flatlist items without refresh the Flatlist/reload in React Native
just like the Chat Applications, when you receive new message from someone down in the list, this person will be the first one on the list.
i have searched a lot and all i could find was adding, removing, drag & drop sortable.
i'm looking for it to happen automatically when the user receive a message that message will be the first on the list.
all the code i have for now is flatlist with dummy data
now lets say i want the id 3 to be number 1 without refresh/reload the flatlist, i know i should be using Animation but im not strong in animation RN.
import { SafeAreaView, View, FlatList, StyleSheet, Text } from 'react-native';
import Constants from 'expo-constants';
const DATA = [
{
id: '1',
title: 'First Item',
},
{
id: '2',
title: 'Second Item',
},
{
id: '3',
title: 'Third Item',
},
];
function Item({ title }) {
return (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
}
export default function App() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: Constants.statusBarHeight,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});
Related
I'm facing an issue with the onViewableItemsChanged prop from the flat-list. I have a list of videos that are being played when a single video comes viewable on the screen, I achived that.
But the issue is, once a video automatically starts playing while scrolling, I navigate to another where I have a text input field. Once the keypad is opened for the text input the onViewableItemsChanged is being called which is in another screen and the video continues playing in the text input screen.
Below is the code of two different screens:
FlatListSample.js
import React, {useState, useCallback} from 'react';
import {StyleSheet, Text, View, FlatList, TouchableOpacity} from 'react-native';
import YouTubeIFrame from 'react-native-youtube-iframe';
const data = [
{
id: '60524193a4e2070001537f51',
title: 'React Native Tutorial #1 - Introduction',
videoLink: 'ur6I5m2nTvk',
},
{
id: '6051f9bba4e2070001537f50',
title: 'React Native Tutorial #2 - Creating a React Native App',
videoLink: 'pflXnUNMsNk',
},
{
id: '6051f98accf9d60001f80429',
title: 'React Native Tutorial #3 - Views, Text & Styles',
videoLink: '_YydVvnjNFE',
},
{
id: '6051f94accf9d60001f80428',
title: 'React Native Tutorial #4 - Using State',
videoLink: '1FiIYaRr148',
},
{
id: '6051f921ccf9d60001f80427',
title: 'React Native Tutorial #5 - Text Inputs',
videoLink: 'c9Sg9jDitm8',
},
{
id: '6051f8e8ccf9d60001f80426',
title: 'React Native Tutorial #6 - Lists & ScrollView',
videoLink: 'W-pg1r6-T0g',
},
{
id: '6051f897a4e2070001537f4f',
title: 'React Native Tutorial #7 - Flat List Component',
videoLink: 'iMCM1NceGJY',
},
{
id: '6051f84ca4e2070001537f4e',
title: 'React Native Tutorial #8 - Touchable Components',
videoLink: 'QhX25YGf8qg',
},
{
id: '6051f817ccf9d60001f80425',
title: 'React Native Tutorial #9 - Todo App (part 1)',
videoLink: 'uLHFPt9B2Os',
},
{
id: '6051f7dba4e2070001537f4d',
title: 'React Native Tutorial #10 - Todo App (part 2)',
videoLink: 'SGEitne8N-Q',
},
];
const FlatListSample = props => {
const [visibleItemIndex, setVisibleItemIndex] = useState();
const [viewabilityConfiguration, setViewabilityConfiguration] = useState({
waitForInteraction: true,
viewAreaCoveragePercentThreshold: 40,
});
const onViewableItemsChangedHandler = useCallback(
({viewableItems, changed}) => {
console.log('Viewable item');
if (viewableItems && viewableItems.length !== 0) {
setVisibleItemIndex(viewableItems[0].index);
}
},
[],
);
const renderItem = ({item, index}) => {
return (
<View key={item.id} style={styles.videoSec}>
<Text style={styles.videoTitle}>{item.title}</Text>
<TouchableOpacity
activeOpacity={0.9}
onPress={() => {
setVisibleItemIndex(null);
props.navigation.navigate('TextInputSample');
}}>
<YouTubeIFrame
videoId={item.videoLink}
height={230}
play={index === visibleItemIndex}
initialPlayerParams={{rel: false, controls: false, loop: true}}
/>
</TouchableOpacity>
</View>
);
};
return (
<View style={styles.container}>
<FlatList
style={{flex: 1}}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
viewabilityConfig={viewabilityConfiguration}
onViewableItemsChanged={onViewableItemsChangedHandler}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F7F7F7',
},
videoSec: {
flex: 1,
paddingVertical: 10,
borderBottomColor: '#FCEABC',
borderBottomWidth: 3,
backgroundColor: '#FFFFFF',
},
videoTitle: {
fontSize: 16,
color: '#1B110A',
paddingHorizontal: 10,
marginBottom: 5,
},
});
export default FlatListSample;
TextInputSample.js
import React from 'react';
import {View, TextInput} from 'react-native';
const TextInputSample = () => {
return (
<View>
<TextInput
style={{height: 40, backgroundColor: 'azure', fontSize: 20}}
placeholder="Type here to translate!"
onChangeText={text => console.log(text)}
/>
</View>
);
};
export default TextInputSample;
When I navigate from FlatListSample.js after some scroll to TextInputSample.js and open keypad the video starts playing again. Can someone please find a solution to this!
Thanking in advance for the solution.
well, i just validated in both IOS and Android. It seems the issue is in android only. also it's weird behavior.
tried to find the cause of the problem by looking at react navigation screens stack, debugged a lot but couldn't track it yet.
in your case i have come up with 2 ways to solve your problem. (open for better solution)
change focused boolean value with navigation eventListeners 'blur' and 'focus'
import React, {useState, useRef, useEffect} from 'react';
import { useCallback } from 'react';
import {StyleSheet, Text, View, FlatList, TouchableOpacity} from 'react-native';
import YouTubeIFrame from 'react-native-youtube-iframe';
const data = [
{
id: '60524193a4e2070001537f51',
title: 'React Native Tutorial #1 - Introduction',
videoLink: 'ur6I5m2nTvk',
},
{
id: '6051f9bba4e2070001537f50',
title: 'React Native Tutorial #2 - Creating a React Native App',
videoLink: 'pflXnUNMsNk',
},
{
id: '6051f98accf9d60001f80429',
title: 'React Native Tutorial #3 - Views, Text & Styles',
videoLink: '_YydVvnjNFE',
},
{
id: '6051f94accf9d60001f80428',
title: 'React Native Tutorial #4 - Using State',
videoLink: '1FiIYaRr148',
},
{
id: '6051f921ccf9d60001f80427',
title: 'React Native Tutorial #5 - Text Inputs',
videoLink: 'c9Sg9jDitm8',
},
{
id: '6051f8e8ccf9d60001f80426',
title: 'React Native Tutorial #6 - Lists & ScrollView',
videoLink: 'W-pg1r6-T0g',
},
{
id: '6051f897a4e2070001537f4f',
title: 'React Native Tutorial #7 - Flat List Component',
videoLink: 'iMCM1NceGJY',
},
{
id: '6051f84ca4e2070001537f4e',
title: 'React Native Tutorial #8 - Touchable Components',
videoLink: 'QhX25YGf8qg',
},
{
id: '6051f817ccf9d60001f80425',
title: 'React Native Tutorial #9 - Todo App (part 1)',
videoLink: 'uLHFPt9B2Os',
},
{
id: '6051f7dba4e2070001537f4d',
title: 'React Native Tutorial #10 - Todo App (part 2)',
videoLink: 'SGEitne8N-Q',
},
];
const FlatListExample = (props) => {
const [visibleItemIndex, setVisibleItemIndex] = useState();
const [focused, setFocused] = useState();
const viewabilityConfig = {
itemVisiblePercentThreshold: 40,
waitForInteraction: true,
};
useEffect(() => {
const subscribeFocusEvent = props.navigation.addListener('focus', () => {
setFocused(true);
console.log('focus', focused);
});
const subscribeBlurEvent = props.navigation.addListener('blur', () => {
setFocused(false);
console.log('blur', focused);
});
return (() => {
subscribeFocusEvent;
subscribeBlurEvent;
});
}, [focused]);
const onViewableItemsChanged = useCallback(({ viewableItems, changed }) => {
console.log({
message: 'triggers change....1',
viewableItems,
changed,
focused
}, 'CHECK');
if (changed && changed.length > 0) {
setVisibleItemIndex(changed[0].index);
}
});
const viewabilityConfigCallbackPairs = useRef([{ viewabilityConfig, onViewableItemsChanged }]);
const renderItem = ({item, index}) => {
return (
<View key={item.id} style={styles.videoSec}>
<Text style={styles.videoTitle}>{item.title}</Text>
<TouchableOpacity
activeOpacity={0.9}
onPress={() => {
setVisibleItemIndex(null);
// props.navigation.navigate('Shop');
}}>
<YouTubeIFrame
videoId={item.videoLink}
height={230}
play={index === visibleItemIndex}
initialPlayerParams={{rel: false, controls: false, loop: true}}
/>
</TouchableOpacity>
</View>
);
};
if(focused) {
return (
<View style={styles.container}>
<FlatList
style={{flex: 1}}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
/>
</View>
);
}
return null;
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F7F7F7',
},
videoSec: {
flex: 1,
paddingVertical: 10,
borderBottomColor: '#FCEABC',
borderBottomWidth: 3,
backgroundColor: '#FFFFFF',
},
videoTitle: {
fontSize: 16,
color: '#1B110A',
paddingHorizontal: 10,
marginBottom: 5,
},
});
export default FlatListExample;
getCurrentRouteName of screen and render flatList. so that way it will render only if it's same screen.
export const FlatListScreen = ({ navigation, route }) => {
console.log(route.name);
// this screen title
if(route.name === 'VideoScreen') {
return (
<FlatList
{...props}
/>
);
}
return null;
};
let me know if you need any clarification any time.
The below code is of Menu.js .I want to navigate to Settings.js by clicking on Settings .
I mentioned the code of Menu.js below.
Can I use the onPress to navigate to the next page wheni click on something?
I don't understand how to add this feature in the below code to the items.
import 'react-native-gesture-handler';
import React, { useState } from 'react';
import { Text, TextInput, View, StyleSheet ,TouchableOpacity,Image,Button,
ImageBackground,FlatList,StatusBar,SafeAreaView} from 'react-native';
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "Tasks Done",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Goals",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Rank",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d74",
title: "Week Plan",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d73",
title: "Settings",
},
];
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text style={styles.title}>{item.title}</Text>
</TouchableOpacity>
);
const Menu = () => {
const [selectedId, setSelectedId] = useState(null);
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#6e3b6e" : "#f9c2ff";
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
style={{ backgroundColor }}
/>
);
};
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 25,
},
});
export default Menu;
I want to navigate to Settings.js as soon as I click on settings .
But I don't want to lose existing function of color changing .
How do I do this??
First of all, it is worth looking at the official docs here: https://reactnative.dev/docs/navigation
Official docs recommend react navigation, have a look at react navigation: https://reactnavigation.org/
Integrate this navigation in your project, once you have this you'd be able to user the navigation.navigate(nameOfYourView).
I am learning React native and was trying to build an app. However, the app is stuck on a white screen and doesn't show anything nor gives any error. This code is going to render a flatlist from an array and will have a delete to swipe button on the right. I am not getting any errors though.
Message.js
import React, { useState } from 'react'
import {
View,
Text,
StyleSheet,
FlatList,
SafeAreaView,
StatusBar,
ItemSeparatorComponent,
Platform
} from 'react-native'
import ListItem from '../components/ListItem'
import ListItemSeparator from '../components/ListItemSeparator'
import DeleteSwipe from '../components/DeleteSwipe'
const messages = [
{
id: 1,
name: 'T1',
description: 'D2',
image: require('../assets/mosh.jpg')
},
{
id: 2,
name: 'T2',
description: 'D2',
image: require('../assets/mosh.jpg')
},
{
id: 3,
name: 'T3',
description: 'D3',
image: require('../assets/mosh.jpg')
},
{
id: 4,
name: 'T4',
description: 'D4',
image: require('../assets/mosh.jpg')
}
]
export default function Message () {
const [messages, setMessage] = useState(messages)
const handleDelete = messages => {
const newMessages = messages.filter(m => m.id != messages.id)
setMessage(newMessages)
}
return (
<SafeAreaView style={styles.screen}>
<FlatList
data={messages}
keyExtractor={messages => messages.id.toString()}
renderItem={({ item }) => (
<ListItem
name={item.name}
description={item.description}
image={item.image}
onPress={() => console.log('touched', item)}
renderRightActions={() => (
<DeleteSwipe onPress={() => handleDelete(item)} />
)}
/>
)}
ItemSeparatorComponent={ListItemSeparator}
/>
<FlatList />
</SafeAreaView>
)
}
const styles = StyleSheet.create({
screen: {
padding: Platform.OS === 'android' ? StatusBar.currentHeight : 0
}
})
DeleteSwipe.js
import React from 'react'
import { View, Text, StyleSheet, TouchableWithoutFeedback } from 'react-native'
import Swipeable from 'react-native-gesture-handler/Swipeable'
import { AntDesign } from '#expo/vector-icons'
const DeleteSwipe = props => {
const { renderRightActions } = props
return (
<TouchableWithoutFeedback onPress={console.log('delete it')}>
<View style={styles.container}>
<AntDesign name='delete' size={24} color='white' />
</View>
</TouchableWithoutFeedback>
)
}
const styles = StyleSheet.create({
container: {
width: 70,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#ff5252'
}
})
export default DeleteSwipe
If it is a debugger issue, Restart the debugger if react native debugger is running. and again start
Or it could be a flexbox issue, Try to add or remove display: flex and flex:1 on this and parent.
Or it could be component is too small, Open inspector from dev menu and check component names in screen.
Change onPress={console.log....} to onPress={() => console.log(...
)}
But it seems what you want is onPress={props.onPress}
I was following a course on React Native with this simple code:
import { StatusBar } from "expo-status-bar";
import React from "react";
import { StyleSheet, Text, View, FlatList } from "react-native";
export default function App() {
const friends = [
{ name: "friend #1" },
{ name: "friend #2" },
{ name: "friend #3" },
{ name: "friend #4" },
{ name: "friend #5" },
{ name: "friend #6" },
{ name: "friend #7" },
{ name: "friend #8" },
];
return (
<View style={styles.container}>
<FlatList
keyExtractor={(friend) => friend.name}
data={friends}
renderItem={({ item }) => {
return <Text>{item.name}</Text>;
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
Here, a warning is supposed to show if we don't add the key extractor and it goes away when we do add it. That is what happens in React Native CLI. But that does not happen in Expo CLI. Is this a bug or is it supposed to be that way in Expo? I'm running the app on an actual phone with android 7.
The warning you are getting means that the elements of the list are missing keys. These unique keys are what allow the Flatlist to track items.
You will have to choose a unique key prop , by adding an other key field to your friends array.
you are still getting a warnning cause the key extractor falls back to use index by default
for Example :
keyExtractor={(item, index) => index.toString()}
Inside the FlatList component :
<FlatList
keyExtractor={(item, index) => index.toString()}
data={friends}
renderItem={({ item }) => {
return <Text>{item.name}</Text>;
}}
/>
I was following tutorial and I got 'ReferenceError can't find variable flatlist' error, then I deleted the code and copied from the github to check if I might missed something and it's still didn't work.
import React, {useState} from 'react';
import {StyleSheet, Text, View,FlatList} from 'react-native';
import Header from './components/header';
export default function App () {
const [todos, setTodos] = useState([
{ text: 'buy coffee', key: '1' },
{ text: 'create an app', key: '2' },
{ text: 'play on the switch', key: '3' }
]);
return (
<View style={styles.container}>
<Header />
<View style={styles.content}>
{/* add todo form */}
<View style={styles.list}>
<FlatList
data={todos}
renderItem={({item}) => (
<Text>{item.text}</Text>
)}
/>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
content:{
padding: 40,
},
list:{
marginTop:20,
}
});
Header :
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
export default function Header() {
return(
<View style={styles.header}>
<Text style={styles.title}>My Todo List</Text>
</View>
)
}
const styles= StyleSheet.create({
header:{
height: 80,
paddingTop: 38,
backgroundColor: 'red',
},
title:{
textAlign: 'center',
color:'#fff',
fontSize: 20,
fontWeight:'bold',
}
});
export default Header;
Perhaps something changed in the version or something else. I will be grateful if you can tell how I can fix the error.
Edit: I changed the casing from Flatlist to FlatList and I got error 'Element type invalid: expected a string (for built- in components)'.
\ Screenshot
change case of Flatlist import as:
import {StyleSheet, Text, View,FlatList} from 'react-native';
check export of your header component. You have exported Header Component two time.
Try Replace Flatlist with FlatList
Correct: import {StyleSheet, Text, View,FlatList} from 'react-native';
Also, try to export as Class, if it's entry point:
import React, { Component } from 'react';
export default class App extends Component {
state = {
todos: [
{ text: 'buy coffee', key: '1' },
{ text: 'create an app', key: '2' },
{ text: 'play on the switch', key: '3' },
],
};
render() {
const { todos } = this.state;
return (
<View style={styles.container}>
<Header />
<View style={styles.content}>
{/* add todo form */}
<View style={styles.list}>
<FlatList
data={todos}
renderItem={({ item }) => <Text>{item.text}</Text>}
/>
</View>
</View>
</View>
);
}
}