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).
Related
Been using Expo and RN on an app, but I'm stuck with a problem. I'm using Expo Video
to make a photo/video gallery. The problem is, if I have more than 1 video in the array, only the last one will play (problem with useRef). And I couldn't find a way to create a ref for each one of them.
Solutions that I've tried and half worked: I created a VideoComponent (as a function then added on return), and each component had its own useRef and useState for playing inside the component a different useRef/useState for video/status for each. It worked okay-ish. But the problem was when other states changed (user presses like, for example). Whenever a state changes, and rerenders, the whole video reset to the beginning. Which is not ok.
The video reset on state change of other components doesn't affect the video if doing it normally (one useRef/state) but as I said, It's only playing the last component, which is not okay.
import React, { useRef, useState } from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
} from 'react-native';
function App(props) {
const [allData, setAllData] = useState([
{
medias: [
{ link: 'https://link.com/link1.avi', mediaExtension: 'avi' },
{ link: 'https://link.com/link2.jpg', mediaExtension: 'jpg' },
{ link: 'https://link.com/link3.mov', mediaExtension: 'mov' },
],
name: 'Name',
description: 'description',
},
]);
const video = useRef(null);
const [status, setStatus] = useState({});
return (
<View style={{}}>
<FlatList
horizontal
data={allData}
renderItem={({ item }) => (
<View style={{}}>
{item.medias.map((item) => (
<View>
{item.mediaExtension === 'mov' || 'avi' || 'WebM' ? (
<View style={{ flex: 1 }}>
<TouchableOpacity
onPress={() =>
video.isPlaying
? video.current.pauseAsync()
: video.current.playAsync()
}>
<Video
ref={video}
style={{ alignSelf: 'center' }}
source={{
uri: item.link,
}}
onPlaybackStatusUpdate={(status) =>
setStatus(() => status)
}
/>
</TouchableOpacity>
</View>
) : (
<Image style={{}} source={{ uri: item.link }} />
)}
</View>
))}
</View>
)}
/>
</View>
);
}
export default App;
As far as I understand, you want to create a FlatList of Videos, and onScroll you want to pause it. This can be implemented as shown below
Also, here is a Working Example for this
import * as React from 'react';
import { Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
import VideoPlayer from './components/VideoPlayer';
const Videos = [
{
_id: 1,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 2,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 3,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 4,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 5,
source: require('./assets/videoplayback.mp4'),
},
{
_id: 6,
source: require('./assets/videoplayback.mp4'),
},
];
export default function App() {
const [Viewable, SetViewable] = React.useState([]);
const ref = React.useRef(null);
const onViewRef = React.useRef((viewableItems) => {
let Check = [];
for (var i = 0; i < viewableItems.viewableItems.length; i++) {
Check.push(viewableItems.viewableItems[i].item);
}
SetViewable(Check);
});
const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 80 });
return (
<View style={styles.container}>
<FlatList
data={Videos}
keyExtractor={(item) => item._id.toString()}
renderItem={({ item }) => <VideoPlayer {...item} viewable={Viewable} />}
ref={ref}
onViewableItemsChanged={onViewRef.current}
viewabilityConfig={viewConfigRef.current}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
and VideoPLayer component looks like this
import * as React from 'react';
import { Text, View, StyleSheet, Dimensions } from 'react-native';
import Constants from 'expo-constants';
import { Video, AVPlaybackStatus } from 'expo-av';
export default function VideoPlayer({ viewable, _id, source }) {
const video = React.useRef(null);
React.useEffect(() => {
if (viewable) {
if (viewable.length) {
if (viewable[0]._id === _id) {
video.current.playAsync();
} else {
video.current.pauseAsync();
}
} else {
video.current.pauseAsync();
}
} else {
video.current.pauseAsync();
}
}, [viewable]);
return (
<View style={styles.container}>
<Video
ref={video}
source={source}
rate={1.0}
volume={1.0}
resizeMode={'contain'}
isLooping
shouldPlay
style={styles.video}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
width: Dimensions.get('window').width,
marginBottom: 100,
marginTop: 100,
},
video: {
width: Dimensions.get('window').width,
height: 300,
},
});
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.
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 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>
);
}
}
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,
},
});