Smooth scrollToOffset in FlatList React Native - javascript

I have tried to sychronise-scroll two Flatlist with state but my thought was that scrolling was shaking, lagging and not smooth due to re-rendering. But I tried with referencing React element but it didn't help. The result is the same, scrolling is like a person gotten electrified and shock, that is, shaking.
Code is below:
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Button } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const listRefOne = React.useRef();
const listRefTwo = React.useRef();
const handleRef = (listRef, offset) => {
if (listRef === listRefOne) {
listRefTwo.current.scrollToOffset({ animated: true, offset: offset });
console.log('One', offset);
}
if (listRef === listRefTwo) {
listRefOne.current.scrollToOffset({ animated: true, offset: offset });
console.log('Two', offset);
}
};
return (
<View style={styles.container}>
<MyListView listRef={listRefOne} handleRef={handleRef} />
<MyListView listRef={listRefTwo} handleRef={handleRef} />
</View>
);
}
const generateData = () => {
const temp = [];
for (var i = 1; i <= 100; i++) {
temp.push({ id: i, title: `# ${i} Hello` });
}
return temp;
};
const mydata = generateData();
const MyListView = ({ listRef, handleRef }) => {
const handleScroll = (offset) => handleRef(listRef, offset);
return (
<FlatList
ref={(list) => {
listRef.current = list;
}}
style={styles.itemView}
data={mydata}
renderItem={({ item }) => (
<Text style={{ fontSize: 20 }}>{item.title}</Text>
)}
keyExtractor={(item) => item.id}
onScroll={(e) => handleScroll(e.nativeEvent.contentOffset.y)}
/>
);
};
const styles = StyleSheet.create({
container: {
flex: 2,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
itemView: {
flexGrow: 1,
backgroundColor: '#efefef',
margin: 3,
},
});
Expo Link

Related

React Native - Trying change 2 View heights with GestureHandler

I am trying to create Height adjustable Views with React Native for an app I am building. I keep getting stuck on this one aspect. I am trying to create two stacked Views, with a line inbetween them so they are height adjustable when dragging the line up or down, adjusting content in it as well. Image below is a representation of what I am trying to make. "Home Option 2" is default state, "Home Option 1.3 is when the slider is dragged down, and "Home Option 1.2" is opposite - slider dragged up.
With an app bar at the bottom. (I dont have it made yet)
Any thoughts or help is appreciated!
Here is my code for App.tsx
import * as React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import BottomSheet, { BottomSheetRefProps } from './components/BottomSheet';
import { useCallback, useRef } from 'react';
import MapView, { Marker, Geojson } from "react-native-maps";
import { PROVIDER_GOOGLE } from "react-native-maps";
export default function App() {
const ref = useRef<BottomSheetRefProps>(null);
const [topViewHeight, setTopViewHeight] = React.useState(0);
const onPress = useCallback(() => {
const isActive = ref?.current?.isActive();
if (isActive) {
ref?.current?.scrollTo(0);
} else {
ref?.current?.scrollTo(-200);
}
}, []);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<View style={styles.mapViewContainer}>
<MapView
provider={PROVIDER_GOOGLE}
showsUserLocation={true}
style={styles.mapView}
initialRegion={{
latitude: 00.00 ,
longitude: -00.00 ,
latitudeDelta: 00.00 ,
longitudeDelta: 00.00 ,
}}
>
<Marker coordinate={{ latitude: 00.00, longitude: 00.00 }} />
</MapView>
</View>
<View style={styles.container}>
<StatusBar style="light" />
<TouchableOpacity style={styles.button} onPress={onPress} />
<BottomSheet ref={ref} {...{setTopViewHeight, topViewHeight}}>
<View style={{ flex: 1, backgroundColor: 'orange' }} />
</BottomSheet>
</View>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#111',
alignItems: 'center',
justifyContent: 'center',
},
button: {
height: 50,
borderRadius: 25,
aspectRatio: 1,
backgroundColor: 'white',
opacity: 0.6,
},
mapViewContainer: {
height: "50%",
width: "95%",
overflow: "hidden",
background: "transparent",
borderRadius: 13,
},
mapView: {
height: "100%",
width: "100%",
},
});
Code for BottomSheet.tsx (Which i was using as a reference for the ideal UX)
import { Dimensions, StyleSheet, Text, View } from 'react-native';
import React, { useCallback, useEffect, useImperativeHandle } from 'react';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
import Animated, {
Extrapolate,
interpolate,
useAnimatedStyle,
useSharedValue,
withSpring,
withTiming,
} from 'react-native-reanimated';
const { height: SCREEN_HEIGHT } = Dimensions.get('window');
const TOP_VIEW_HEIGHT = 50;
const VIEW_RESIZE = 2.5;
const MAX_TRANSLATE_Y = -SCREEN_HEIGHT / VIEW_RESIZE;
type BottomSheetProps = {
children?: React.ReactNode;
setTopViewHeight: (height: number) => void;
topViewHeight: number;
};
export type BottomSheetRefProps = {
scrollTo: (destination: number) => void;
isActive: () => boolean;
};
const BottomSheet = React.forwardRef<BottomSheetRefProps, BottomSheetProps>(
({ children }, ref) => {
const translateY = useSharedValue(0);
const active = useSharedValue(false);
const scrollTo = useCallback((destination: number) => {
'worklet';
active.value = destination !== 0;
translateY.value = withSpring(destination, { damping: 50 });
}, []);
const isActive = useCallback(() => {
return active.value;
}, []);
useImperativeHandle(ref, () => ({ scrollTo, isActive }), [
scrollTo,
isActive,
]);
const context = useSharedValue({ y: 0 });
const gesture = Gesture.Pan()
.onStart(() => {
context.value = { y: translateY.value };
})
.onUpdate((event) => {
translateY.value = event.translationY + context.value.y;
translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y);
console.log(translateY.value);
})
.onEnd(() => {
if (translateY.value > -SCREEN_HEIGHT / 3) {
scrollTo(0);
} else if (translateY.value < -SCREEN_HEIGHT / 1.5) {
scrollTo(MAX_TRANSLATE_Y);
}
console.log('end: ' + translateY.value)
});
const rBottomSheetStyle = useAnimatedStyle(() => {
const borderRadius = interpolate(
translateY.value,
[MAX_TRANSLATE_Y + 50, MAX_TRANSLATE_Y],
[25, 5],
Extrapolate.CLAMP
);
return {
borderRadius,
transform: [{ translateY: translateY.value }],
maxHeight: 500,
};
});
return (
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.bottomSheetContainer, rBottomSheetStyle] }>
<View style={styles.line} />
{children}
</Animated.View>
</GestureDetector>
);
}
);
const styles = StyleSheet.create({
bottomSheetContainer: {
minHeight: SCREEN_HEIGHT - 50,
width: '100%',
backgroundColor: 'white',
position: 'relative',
top: SCREEN_HEIGHT - 500,
borderRadius: 25,
},
line: {
width: 75,
height: 4,
backgroundColor: 'grey',
alignSelf: 'center',
marginVertical: 15,
borderRadius: 2,
},
});
export default BottomSheet;
The Bar component will have the GestureHandler tied to it. Interpolate yTranslation into a value between 0 and 1. The Bar component's SharedValue is passed as prop so that other components in its parent contain utilize it:
import {
StyleSheet,
ViewStyle,
Dimensions,
View,
useWindowDimensions,
} from 'react-native';
import Animated, {
SharedValue,
useAnimatedStyle,
interpolate,
withTiming,
} from 'react-native-reanimated';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
type Props = {
anim: SharedValue<number>;
style?: ViewStyle;
};
const snapPoints = [0.2, 0.5, 0.8];
export default function Bar({ anim, style }: Props) {
const { height } = useWindowDimensions();
const gesture = Gesture.Pan()
.onUpdate((e) => {
// interpolate yTranslation to a value that snapPoints can work with
anim.value = interpolate(
e.translationY,
[-height * 0.5, height * 0.5],
[0, 1]
);
})
// snap to nearest point
.onEnd(() => {
const snapPoint = snapPoints.reduce((prev, curr) => {
const prevDist = Math.abs(prev - anim.value);
const currDist = Math.abs(curr - anim.value);
return prevDist < currDist ? prev : curr;
}, snapPoints[0]);
console.log('snapping to ', snapPoint);
// animate snapping to snapPoint
anim.value = withTiming(snapPoint);
});
return (
<GestureDetector gesture={gesture}>
<View style={styles.barContainer}>
<View style={styles.bar} />
</View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
barContainer: {
backgroundColor: 'transparent',
width: '100%',
//padding to make bar easier to press
padding: 10,
justifyContent: 'center',
},
bar: {
backgroundColor: '#c4c4c4',
width: '80%',
height: 7,
alignSelf: 'center',
borderRadius: 25,
},
});
Now that translationY is a percentage it can be used to determine the amount of flex each view have:
import React from 'react';
import {
View,
StyleSheet,
} from 'react-native';
import Constants from 'expo-constants';
import Animated, {
useSharedValue,
useAnimatedStyle,
} from 'react-native-reanimated';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import SliderBar from './SliderBar';
import View1 from './View1';
import View2 from './View2';
import { footerHeight, ScreenWidth, ScreenHeight, MAX_FLEX } from './Constants';
export default function App() {
const barValue = useSharedValue(0.5);
const view1Style = useAnimatedStyle(() => {
return {
flex: barValue.value * MAX_FLEX,
};
});
const view2Style = useAnimatedStyle(() => {
return {
flex: Math.abs(barValue.value - 1) * MAX_FLEX,
};
});
return (
<GestureHandlerRootView
style={{ width: ScreenWidth, height: ScreenHeight }}>
<View style={styles.container}>
<Animated.View style={[styles.viewStyle, view1Style]}>
<View1 />
</Animated.View>
<SliderBar anim={barValue} />
<Animated.View style={[styles.viewStyle, view2Style]}>
<View2 />
</Animated.View>
<View style={styles.footer} />
</View>
</GestureHandlerRootView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
padding: 8,
margin: 5,
},
viewStyle: {
backgroundColor: '#c4c4c4',
flex: 1,
marginVertical: 10,
borderRadius: 10,
},
footer: {
backgroundColor: '#6f6f6f',
height: footerHeight,
borderRadius: 10,
},
});
Demo

Trying to come out with a filter function for my app. Render Error: Too many re-renders. React limits the number of renders

The idea I have for this to work is to copy my main array from firebase (Array with all my info) into a temporary array. Then I will filter this temporary array and have it displayed in flatlist. The onPress for the buttons serves to select the type of information to be filtered (Eg type 1 or 2 or 3).
import React, { useState, setState, useEffect } from 'react';
import { View, Text, StyleSheet, ImageBackground, FlatList, Button, TouchableHighlight } from 'react-native'
import Card from '../components/Card';
import colors from '../config/colors';
import {MaterialCommunityIcons} from '#expo/vector-icons'
import { useNavigation } from '#react-navigation/core';
import AppButton from '../components/AppButton'
import { SearchBar } from 'react-native-screens';
import { Firestore, getDoc, collection, getDocs,
addDoc, deleteDoc, doc,
query, where, onSnapshot
} from 'firebase/firestore';
import {db} from '../../firebase';
import { async } from '#firebase/util';
//run: 1
//swim: 2
//cycle: 3
function EventsPage(props) {
const [events, setEvents] = useState([]);
const [bool, setBool] = useState(false);
const [arr, setArr] = useState([])
const colRef = collection(db, 'events');
const q = query(colRef, where('type', '>=', 0))
onSnapshot(q, (snapshot) => {
const events = []
snapshot.docs.forEach((doc) => {
events.push({...doc.data()}) //put the data into an array
})
if (bool === false) {
setEvents(events);
setBool(true)
}
})
const updateSearch = search => {
setArr({ search }, () => {
if (type == search) {
setArr({
data: [...arr.temp]
});
return;
}
arr.data = arr.temp.filter(function(item){
return item.name.includes(search);
}).map(function({date, subTitle, title, type}){
return {date, subTitle, title, type};
});
});
};
return (
<View style = {styles.container}>
<ImageBackground
source = {require('../assets/splash-page.jpg')}
style = {{width: '100%', height: '100%'}}
blurRadius={8}
>
<View style = {styles.backIcon}>
<MaterialCommunityIcons name='arrow-left-bold' color="black" size={35} onPress={() => {
navigation.replace("Connect_me")
}} />
</View>
<Text style = {styles.text}>EVENTS</Text>
<View style = {styles.buttons}>
<Button title={'All'} />
<Button title={'Run'} onPress = {updateSearch(1)}/>
<Button title={'Swim'} onPress = {updateSearch(2)}/>
<Button title={'Cycle'} onPress = {updateSearch(3)}/>
</View>
<FlatList
data={arr.data}
renderItem={({ item }) => (
<View style = {styles.cardContainer}>
<Card title={item.title} subTitle = {item.subTitle}/>
</View>
)}
/>
<Text></Text>
<Text></Text>
<Text></Text>
<Text></Text>
<Text></Text>
</ImageBackground>
</View>
// trolling
);
}
const styles = StyleSheet.create({
text: {
fontSize: 80,
textAlign:'center',
paddingBottom: 20,
color: colors.primary,
fontWeight: 'bold',
},
container: {
backgroundColor: 'white',
},
cardContainer: {
width: '95%',
alignSelf: 'center'
},
backIcon: {
paddingLeft: 10,
paddingTop: 30,
},
searchIcon: {
paddingLeft: 10,
paddingTop: 15,
position: 'relative',
left: 330,
bottom: 47
},
buttons: {
flexDirection: 'row',
padding: 20,
}
})
export default EventsPage;
Side effects code like listening to data change events should be handled inside the useEffect hook.
The app continues to listen to data change events for each component re-render which causes an infinity loop.
useEffect(() => {
const unsubscribe = onSnapshot(q, (snapshot) => {
const events = [];
snapshot.docs.forEach((doc) => {
events.push({ ...doc.data() }); //put the data into an array
});
if (bool === false) {
setEvents(events);
setBool(true);
}
});
// unsubscribe to data change events when component unmount
return () => {
unsubscribe();
};
}, []);

How can I properly layer elements in JavaScript?

I am working on a (what I thought was) simple agenda app. Using React-Native Calendars to add an Agenda to my page. I wanted to create functionality to add items to the Agenda. I added a placeholder API to fill the Agenda with items so I can add additional styling before I enter in my own logic. I am trying to add a "+" button that will open a prompt to add an item to the Agenda. However, I cannot get the item to stack on top of the Agenda View.
import * as React from 'react';
import {View, StyleSheet, Text, TouchableOpacity, TouchableOpacityComponent, Platform} from 'react-native';
import {Agenda} from 'react-native-calendars';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {useEffect, useState} from "react";
import {addDays, format} from 'date-fns';
import {KeyboardAvoidingView, Touchable} from "react-native-web";
import {ScrollView} from "react-native-gesture-handler";
export default function CalendarView() {
type Item = {
name: string;
}
type Post = {
id: number;
title: string;
body: string;
userId: number;
};
const [items, setItems] = useState();
useEffect(() => {
// run once
const getData = async () => {
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts',
);
const data: Post[] = await response.json();
const mappedData = data.map((post, index) => {
const date = addDays(new Date(), index);
return {
...post,
date: format(date, 'yyyy-MM-dd'),
}
})
const reduced = mappedData.reduce(
(acc: { [key: string]: Post[] }, currentItem) => {
const {date, ...coolItem} = currentItem;
acc[date] = [coolItem];
return acc;
},
{},
)
setItems(reduced);
}
getData();
}, []);
const renderItem = (item: Item) => {
return (
<View style={styles.itemContainer}>
<Text>{item.name}</Text>
</View>
);
};
return (
<View style={styles.container}>
<Agenda items={items} renderItem={renderItem}
style={styles.calendarWrapper}
scrollEnabled={true}
theme={{
// calendarBackground: '#000000'
todayTextColor: '#00adf5',
}}>
</Agenda>
<View behavior={Platform.OS === "ios" ? "padding" : "height"}>
<TouchableOpacity onPress={() => console.log("button pressed")}>
<View style={styles.addWrapper}>
<Ionicons name={'add-outline'} size={30} color={'black'}/>
</View>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
calendarWrapper: {},
items: {},
dayPressColor: {
backgroundColor: '#000000'
},
itemContainer: {
backgroundColor: 'white',
margin: 5,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
addWrapper: {
width: 100,
height: 100,
backgroundColor: '#55BCF6',
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#C0C0C0',
borderWidth: 1,
shadowRadius: 5,
shadowOpacity: 100
},
})
Image of the UI so Far
I am extremely new to JS and CSS in general so any help would be appreciated. If I can't get a button to be placed correctly where I want it, then adding the functionality will definitely be a challenge!

ERROR Warning: Failed prop type: Invalid props.style key `elevation` supplied to `Image`

I am Creating a Tinder Clone in React Native and working on UI. But having some difficulty in showing images on top of the screen. I used zIndex but it didn't effect because it doesn't work on Android, I used elevation but it is giving me the error plus warning too. Here is the Code
import React, {useEffect, useState} from 'react';
import {
View,
StyleSheet,
useWindowDimensions,
Image,
Platform,
} from 'react-native';
import Card from './src/components/TinderCard';
import users from './assets/data/users';
import Animated, {
useSharedValue,
useAnimatedStyle,
useAnimatedGestureHandler,
useDerivedValue,
interpolate,
withSpring,
runOnJS,
} from 'react-native-reanimated';
import 'react-native-gesture-handler';
import {PanGestureHandler} from 'react-native-gesture-handler';
import like from './assets/images/LIKE.png';
import nope from './assets/images/nope.png';
const ROTATION = 60;
const SWIPE_VELOCITY = 800;
const App = () => {
const [currentIndex, setCurrentIndex] = useState(0);
const [nexttIndex, setNextIndex] = useState(currentIndex + 1);
const currentProfile = users[currentIndex];
const nextProfile = users[nexttIndex];
const {width: screenWidth} = useWindowDimensions();
const hiddenTranslateX = 2 * screenWidth;
const translateX = useSharedValue(0);
const rotate = useDerivedValue(
() =>
interpolate(translateX.value, [0, hiddenTranslateX], [0, ROTATION]) +
'deg',
);
const cardStyle = useAnimatedStyle(() => ({
transform: [
{
translateX: translateX.value,
},
{rotate: rotate.value},
],
}));
const nextCardStyle = useAnimatedStyle(() => ({
transform: [
{
scale: interpolate(
translateX.value,
[-hiddenTranslateX, 0, hiddenTranslateX],
[1, 0.8, 1],
),
},
],
opacity: interpolate(
translateX.value,
[-hiddenTranslateX, 0, hiddenTranslateX],
[1, 0.5, 1],
),
}));
const gestureHandler = useAnimatedGestureHandler({
onStart: (_, context) => {
context.startX = translateX.value;
},
onActive: (event, context) => {
translateX.value = context.startX + event.translationX;
},
onEnd: event => {
if (Math.abs(event.velocityX) < SWIPE_VELOCITY) {
translateX.value = withSpring(0);
return;
}
translateX.value = withSpring(
hiddenTranslateX * Math.sign(event.velocityX),
{},
() => runOnJS(setCurrentIndex)(currentIndex + 1),
);
},
});
useEffect(() => {
translateX.value = 0;
setNextIndex(currentIndex + 1);
}, [currentIndex, translateX]);
return (
<View style={styles.container}>
{nextProfile && (
<View style={styles.nextCardContainer}>
<Animated.View style={[styles.animatedCard, nextCardStyle]}>
<Card user={nextProfile} />
</Animated.View>
</View>
)}
{currentProfile && (
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.animatedCard, cardStyle]}>
<Image source={like} style={styles.like} resizeMode="contain" />
<Image source={nope} style={styles.like} resizeMode="contain" />
<Card user={currentProfile} />
</Animated.View>
</PanGestureHandler>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
animatedCard: {
width: '90%',
height: '70%',
justifyContent: 'center',
alignItems: 'center',
},
nextCardContainer: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
...StyleSheet.absoluteFillObject,
},
like: {
width: 150,
height: 150,
position: 'absolute',
top: 10,
zIndex: 1,
elevation: 1,
},
});
export default App;
Help me to figure out what i am doing wrong here.
Have you tried using an ImageBackground instead? If you're trying to add box-shadow then and React native image background example

using Onclick, fetch api data in react native

I am new to React Native.
I am facing an issue with this view. Basically it is something like this when you click a button it generates any random number, now this random number becomes an id and it goes to at the end of the API url, And using this new API - with ID at the end of it. - data gets fetched. Now i've divided this task in two parts generating random number code (i.e. snippet 1) and fetching data from api ( i.e. snippet 2). As of now, I don't know how to combine them because i am new to react native so a little help here would be appreciated from anyone.
Snipppet 1
import { StyleSheet, View, Button, Text } from 'react-native';
export default class MyProject extends Component {
constructor(){
super();
this.state={
// This is our Default number value
NumberHolder : 0
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1 ;
this.setState({
NumberHolder : RandomNumber
})
}
render() {
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
Snippet 2
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const fetchData = async () => {
const resp = await fetch("https://jsonplaceholder.typicode.com/photos/7");
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
Thanks in advance!!
I think you must understand components clearly! React is component based! But your case is not 2 components! You have a component for fetching api and showing in list! Generating a random number is not a component, but it is a method(or function) in your list component! I think it is better to use one component for list and wrap a function to it for generating random number.
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const generatRandomNumber = () => {
return Math.floor(Math.random() * 5000) + 1
}
const fetchData = async () => {
const resp = await fetch(`https://jsonplaceholder.typicode.com/photos/${generatRandomNumber()}`);
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
But if you want to passing data between components you are have, it is not related to function or class component and you can pass data between them with props! So your code like this:
Random Number Component
import { StyleSheet, View, Button, Text } from 'react-native';
export default class MyProject extends Component {
constructor(props){ //edited
super(props); //edited
this.state={
// This is our Default number value
NumberHolder : 0
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1 ;
this.props.randomNumber(RandomNumber)
}
render() {
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});
Your list component:
import React, { useState } from "react";
import { Box, FlatList, Center, NativeBaseProvider, Button } from "native-base";
import { StyleSheet, View, ActivityIndicator, Text, TouchableOpacity, Image } from 'react-native';
// import MyProject
export default function MyFUnction() {
const [data, setData] = useState(null);
const [visible, setVisible] = useState(true);
const [number, setNumber] = useState(null);
const fetchData = async () => {
const resp = await fetch(`https://jsonplaceholder.typicode.com/photos/${number}`);
const data = await resp.json();
setData(data);
setVisible(false);
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.list}>
<Text>{item.title}</Text>
</TouchableOpacity>
);
};
return (
<NativeBaseProvider>
<Center flex={1}>
<MyProject radomNumber={(number) => setNumber(number)}
{visible && <Button onPress={() => fetchData()}>Press</Button>}
{data && (
<FlatList
data={data}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item) => item.id.toString()}
/>
)}
</Center>
</NativeBaseProvider>
);
}
const styles = StyleSheet.create({
list: {
paddingVertical: 4,
margin: 5,
backgroundColor: '#fff',
},
});
thanks everyone for helping me.
here i am posting answer to my question, if anybody in future need an answer.
import React, { useEffect, useState, Component } from 'react';
import { StyleSheet, View, Button, FlatList, Text, Image } from 'react-native';
export default class MyProject extends Component {
constructor(){
super();
this.state={
// This is our Default number value
NumberHolder : 1,
books: []
}
}
GenerateRandomNumber=()=>
{
var RandomNumber = Math.floor(Math.random() * 5000) + 1;
fetch(`https://jsonplaceholder.typicode.com/photos/${RandomNumber}`)
.then((response) => response.json())
.then(booksList => {
this.setState({ books: booksList });
});
this.setState({
NumberHolder : RandomNumber
})
}
render() {
let Image_Http_URL ={ uri: 'https://reactnativecode.com/wp-content/uploads/2017/05/react_thumb_install.png'};
return (
<View style={styles.MainContainer} >
<Text style={{marginBottom: 10, fontSize: 20}}>{this.state.NumberHolder}</Text>
<Image
style={{width: '100%', height: 200,resizeMode : 'stretch' }}
source={{uri: this.state.books.url}}
/>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.title}</Text>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.url}</Text>
<Text style={{marginBottom: 10, fontSize: 12}}>{this.state.books.thumbnailUrl}</Text>
<Button title="Generate Random Number" onPress={this.GenerateRandomNumber} />
</View>
);
}
}
const styles = StyleSheet.create(
{
MainContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
});

Categories