I am making an infinite image carousel using hooks and javascript in react native.
I am almost done with the code and also the carousel works absolutely fine but the active dots below the carousel runs faster than the images. I have tried a couple of things but unfortunately it didn't worked out.
Thanks in advance.
import React, {
useEffect,
useState,
useRef,
useCallback,
createRef,
} from 'react';
import {
StyleSheet,
View,
Dimensions,
FlatList,
LayoutAnimation,
UIManager,
Text,
} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = ({data}) => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [index, setIndex] = useState(0);
const [dataState, setDataState] = useState(data);
slider = createRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}, []);
viewabilityConfig = {
viewAreaCoveragePercentThreshold: 50,
};
const onViewableItemsChanged = ({viewableItems, changed}) => {
if (viewableItems.length > 0) {
let currentIndex = viewableItems[0].index;
if (currentIndex % data.length === data.length - 1) {
setIndex(currentIndex),
setDataState(dataState => [...dataState, ...data]);
} else {
console.log(currentIndex, 'else');
setIndex(currentIndex);
}
}
};
const onSlideChange = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeIn);
const newIndex = index + 1;
setIndex(newIndex);
slider?.current?.scrollToIndex({
index: index,
animated: true,
});
};
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
clearInterval(intervalId);
};
}, [onSlideChange]);
const viewabilityConfigCallbackPairs = useRef([
{viewabilityConfig, onViewableItemsChanged},
]);
const renderIndicator = ()=>{
const indicators = [];
data.map((val,key)=>(
indicators.push(
<Text
key={key}
style={
key === index % data.length ? {color: 'lightblue',fontSize:10,marginBottom: 8,marginHorizontal:1} :
{color: '#888',fontSize:10,marginBottom: 8,marginHorizontal:1}
}>
⬤
</Text>
)
));
return indicators;
}
return (
<View style={{width: dimension.width,height: 280, backgroundColor: '#fff'}}>
<FlatList
ref={slider}
horizontal
pagingEnabled
snapToInterval={dimension?.width}
decelerationRate="fast"
bounces={false}
showsHorizontalScrollIndicator={false}
data={dataState}
renderItem={({item, index}) => (
<>
<View>
<Image
source={{uri: `${item.url}`}}
style={{
width: dimension?.width,
height: 250,
resizeMode: 'cover',
}}
PlaceholderContent={<ActivityIndicator />}
/>
</View>
</>
)}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
getItemLayout={(data, index) => ({
length: dimension?.width,
offset: dimension?.width * index,
index,
})}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
removeClippedSubviews={true}
/>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{renderIndicator()}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
The data that is passed as the props to this component is
export const carouselImages = [
{url: 'https://i.ibb.co/FDwNR9d/img1.jpg'},
{url: 'https://i.ibb.co/7G5qqGY/1.jpg'},
{url: 'https://i.ibb.co/Jx7xqf4/pexels-august-de-richelieu-4427816.jpg'},
{url: 'https://i.ibb.co/GV08J9f/pexels-pixabay-267202.jpg'},
{url: 'https://i.ibb.co/sK92ZhC/pexels-karolina-grabowska-4210860.jpg'},
];
Ooooooh, I fixed it myself
Here is the perfectly working code full code. 😄
import React, {
useEffect,
useState,
useRef,
useCallback,
createRef,
} from 'react';
import {
StyleSheet,
View,
Dimensions,
FlatList,
LayoutAnimation,
UIManager,
Text,
} from 'react-native';
import {ActivityIndicator} from 'react-native';
import {Image} from 'react-native-elements';
const HomeCarousel = ({data}) => {
const [dimension, setDimension] = useState(Dimensions.get('window'));
const [index, setIndex] = useState(0);
const [dataState, setDataState] = useState(data);
const [indicatorIndex, setindicatorIndex] = useState();
slider = createRef();
let intervalId = null;
const onChange = () => {
setDimension(Dimensions.get('window'));
};
useEffect(() => {
Dimensions.addEventListener('change', onChange);
return () => {
Dimensions.removeEventListener('change', onChange);
};
});
useEffect(() => {
if (Platform.OS === 'android') {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}, []);
viewabilityConfig = {
viewAreaCoveragePercentThreshold: 50,
};
const onViewableItemsChanged = ({viewableItems, changed}) => {
if (viewableItems.length > 0) {
let currentIndex = viewableItems[0].index;
if (currentIndex % data.length === data.length - 1) {
setIndex(currentIndex), setindicatorIndex(currentIndex);
setDataState(dataState => [...dataState, ...data]);
} else {
console.log(currentIndex, 'else');
setIndex(currentIndex);
setindicatorIndex(currentIndex);
}
}
};
const onSlideChange = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeIn);
const newIndex = index + 1;
setIndex(newIndex);
slider?.current?.scrollToIndex({
index: index,
animated: true,
});
};
const startInterval = useCallback(() => {
intervalId = setInterval(onSlideChange, 3000);
}, [onSlideChange]);
useEffect(() => {
startInterval();
return () => {
clearInterval(intervalId);
};
}, [onSlideChange]);
const viewabilityConfigCallbackPairs = useRef([
{viewabilityConfig, onViewableItemsChanged},
]);
const renderIndicator = () => {
const indicators = [];
data.map((val, key) =>
indicators.push(
<Text
key={key}
style={
key === indicatorIndex % data.length
? {
color: 'lightblue',
fontSize: 10,
marginBottom: 8,
marginHorizontal: 1,
}
: {
color: '#888',
fontSize: 10,
marginBottom: 8,
marginHorizontal: 1,
}
}>
⬤
</Text>,
),
);
return indicators;
};
return (
<View
style={{width: dimension.width, height: 280, backgroundColor: '#fff'}}>
<FlatList
ref={slider}
horizontal
pagingEnabled
snapToInterval={dimension?.width}
decelerationRate="fast"
bounces={false}
showsHorizontalScrollIndicator={false}
data={dataState}
renderItem={({item, index}) => (
<>
<View>
<Image
source={{uri: `${item.url}`}}
style={{
width: dimension?.width,
height: 250,
resizeMode: 'cover',
}}
PlaceholderContent={<ActivityIndicator />}
/>
</View>
</>
)}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
getItemLayout={(data, index) => ({
length: dimension?.width,
offset: dimension?.width * index,
index,
})}
windowSize={1}
initialNumToRender={1}
maxToRenderPerBatch={1}
removeClippedSubviews={true}
/>
<View
style={{
flexDirection: 'row',
position: 'absolute',
bottom: 0,
alignSelf: 'center',
}}>
{renderIndicator()}
</View>
</View>
);
};
const styles = StyleSheet.create({});
export default HomeCarousel;
Related
my code works but for some reason, I get this warning:
"Warning: Cannot update a component from inside the function body of a different component."
I think it is something to do with these lines (whan i add them i get the error):
const product = state.data.find((data) => data._id === id);
useEffect(() => {
if ((product.moistureSensor.tests !== undefined) || (product.lightSensor.tests !== undefined)) {
setDataState({ 'lightSensor': product.lightSensor.tests[product.lightSensor.tests.length - 1].status, 'muisterSensor': product.moistureSensor.tests[product.moistureSensor.tests.length - 1].status });
console.log(stateData);
}
}, []);
there is probably something logical in react that I don't understand.
this is the full code -
import React, { useContext, useEffect, useState, useRef } from 'react';
import {
Text,
StyleSheet,
Switch,
Button,
TouchableOpacity, SafeAreaView, View, ActivityIndicator
} from 'react-native';
import { client } from '../../api/SocketConfig'
import { NavigationEvents } from 'react-navigation';
import { Context as ProductDataContext } from '../../context/ProductDetailContext'
import DynamicProgressCircle from '../../components/DynamicProgressCircle';
const SensorDataShow = ({ id }) => {
const { state } = useContext(ProductDataContext);
const [isEnabled, setIsEnabled] = useState(false);
const [loading, setLoading] = useState(false);
const [stateData, setDataState] = useState({ 'lightSensor': null, 'muisterSensor': null });
const listener = (dataServer) => {
console.log(`the data from server:${dataServer}`);
if (dataServer.lightSensor !== null)
setDataState({ 'lightSensor': dataServer.lightSensor, 'muisterSensor': dataServer.muisterSensor });
setLoading(false)
}
const changeData = () => { client.on("showData", listener) }
const emitGetData = () => { client.emit("GetData", id) }
let timer = useRef(null);
useEffect(() => {
if (loading === true) {
console.log('timeout started')
timer.current = setTimeout(() => {
setLoading(false)
console.log('i am after timeout');
}, 35000);
} return () => clearTimeout(timer.current);
}, [loading]);
const product = state.data.find((data) => data._id === id);
useEffect(() => {
if ((product.moistureSensor.tests !== undefined) || (product.lightSensor.tests !== undefined)) {
setDataState({ 'lightSensor': product.lightSensor.tests[product.lightSensor.tests.length - 1].status, 'muisterSensor': product.moistureSensor.tests[product.moistureSensor.tests.length - 1].status });
console.log(stateData);
}
}, []);
useEffect(() => {
changeData();
return () => {
client.removeAllListeners('showData', listener);
}
}, []);
return (
<>
{stateData.muisterSensor !== null && (
<>
<Text style={{ fontSize: 28 }}>Moister sensor data:</Text>
<DynamicProgressCircle
changingValues={{
Percent: parseInt(
stateData.muisterSensor
),
}}
/>
</>
)}
{stateData.lightSensor !== null && (
<Text style={{ fontSize: 28 }}>
Light sensor data:
{
stateData.lightSensor
}
</Text>
)}
{loading === false ?
<Button
title="Get Data"
style={styles.button}
onPress={() => {
emitGetData(id), setLoading(true)
}}
/>
: <ActivityIndicator animating={true} size="large" color="red" />}
</>
);
};
const styles = StyleSheet.create({
button: {
alignItems: 'center',
backgroundColor: '#00CC00',
padding: 10,
marginTop: 10,
},
buttonON: {
alignItems: 'center',
backgroundColor: '#00CC00',
padding: 10,
marginTop: 10,
},
buttonOFF: {
alignItems: 'center',
backgroundColor: '#DB2828',
padding: 10,
marginTop: 10,
},
buttonNotOnline: {
alignItems: 'center',
backgroundColor: '#9B9D9A',
padding: 10,
marginTop: 10,
},
switch: {
alignItems: 'center',
},
});
export default SensorDataShow;
<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>
I appreciate any help I can get !
I can not figure out how I can play selected track/song from flatlist, I already had a playerscreen.js where I can play songs from my array of songs. I want to achieve users searching for songs and play the song from the selected list from the flatlist. Below is my songlist.js
const Songlist = () => {
const [loading, setLoading] = useState(false);
const navigation = useNavigation();
renderFooter = () => {
if (!loading) return null
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}
>
<ActivityIndicator animating size='large' />
</View>
)
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '86%',
backgroundColor: '#CED0CE',
marginLeft: '5%',
}}
/>
)
}
return (
<View>
<FlatList
data={songs}
keyExtractor={item => item.id}
renderItem={({ item, index }) => (
<TouchableOpacity
onPress={() => navigation.navigate('Player')}
>
<View
style={{
flexDirection: 'row',
padding: 16,
alignItems: 'center',
}}
>
<Avatar
source={{ uri: item.artwork.thumbnail }}
size='giant'
style={{ marginRight: 16 }}
/>
<Text
category='s1'
style={{color: '#000'}}
>{`${item.title}`}</Text>
</View>
<Text
category='s2'
style={{color: '#999', marginHorizontal: 80, bottom: 20}}
>Genre: {`${item.genre}`}</Text>
</TouchableOpacity>
)}
ItemSeparatorComponent={renderSeparator}
ListFooterComponent={renderFooter}
/>
</View>
);
}
export default Songlist;
This is my initial playerscreen.js
export default function PlayerScreen() {
const navigation = useNavigation();
const scrollX = useRef(new Animated.Value(0)).current;
const slider = useRef(null);
const isPlayerReady = useRef(false);
const index = useRef(0);
const [songIndex, setSongIndex] = useState(0);
const isItFromUser = useRef(true);
// for tranlating the album art
const position = useRef(Animated.divide(scrollX, width)).current;
const playbackState = usePlaybackState();
useEffect(() => {
// position.addListener(({ value }) => {
// console.log(value);
// });
scrollX.addListener(({value}) => {
const val = Math.round(value / width);
setSongIndex(val);
});
TrackPlayer.setupPlayer().then(async () => {
// The player is ready to be used
console.log('Player ready');
// add the array of songs in the playlist
await TrackPlayer.reset();
await TrackPlayer.add(songs);
TrackPlayer.play();
isPlayerReady.current = true;
await TrackPlayer.updateOptions({
stopWithApp: false,
alwaysPauseOnInterruption: true,
capabilities: [
Capability.Play,
Capability.Pause,
Capability.SkipToNext,
Capability.SkipToPrevious,
],
});
//add listener on track change
TrackPlayer.addEventListener(Event.PlaybackTrackChanged, async (e) => {
console.log('song ended', e);
const trackId = (await TrackPlayer.getCurrentTrack()) - 1; //get the current id
console.log('track id', trackId, 'index', index.current);
if (trackId !== index.current) {
setSongIndex(trackId);
isItFromUser.current = false;
if (trackId > index.current) {
goNext();
} else {
goPrv();
}
setTimeout(() => {
isItFromUser.current = true;
}, 200);
}
// isPlayerReady.current = true;
});
//monitor intterupt when other apps start playing music
TrackPlayer.addEventListener(Event.RemoteDuck, (e) => {
// console.log(e);
if (e.paused) {
// if pause true we need to pause the music
TrackPlayer.pause();
} else {
TrackPlayer.play();
}
});
});
return () => {
scrollX.removeAllListeners();
TrackPlayer.destroy();
// exitPlayer();
};
}, []);
// change the song when index changes
useEffect(() => {
if (isPlayerReady.current && isItFromUser.current) {
TrackPlayer.skip(songs[songIndex].id)
.then((_) => {
console.log('changed track');
})
.catch((e) => console.log('error in changing track ', e));
}
index.current = songIndex;
}, [songIndex]);
const exitPlayer = async () => {
try {
await TrackPlayer.stop();
} catch (error) {
console.error('exitPlayer', error);
}
};
const goNext = async () => {
slider.current.scrollToOffset({
offset: (index.current + 1) * width,
});
await TrackPlayer.play();
};
const goPrv = async () => {
slider.current.scrollToOffset({
offset: (index.current - 1) * width,
});
await TrackPlayer.play();
};
const renderItem = ({index, item}) => {
return (
<Animated.View
style={{
alignItems: 'center',
width: width,
transform: [
{
translateX: Animated.multiply(
Animated.add(position, -index),
-100,
),
},
],
}}>
<Animated.Image
source={item.artwork}
style={{width: 320, height: 320, borderRadius: 5}}
/>
</Animated.View>
);
};
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={{height: 320}}>
<Animated.FlatList
ref={slider}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
scrollEventThrottle={16}
data={songs}
renderItem={renderItem}
keyExtractor={(item) => item.id}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}],
{useNativeDriver: true},
)}
/>
</SafeAreaView>
<TouchableOpacity
style={styles.genreContainer}
onPress={() => navigation.navigate('Genre')}
>
<SimpleLineIcons name="playlist" size={20} color='#fff' />
<Text style={styles.genre}> Genre</Text>
</TouchableOpacity>
<View>
<Text style={styles.title}>{songs[songIndex].title}</Text>
<Text style={styles.artist}>{songs[songIndex].artist}</Text>
</View>
<SliderComp />
<Controller onNext={goNext} onPrv={goPrv} />
</SafeAreaView>
);
}
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar, ScrollView, TouchableOpacity } from 'react-native';
import Sound from 'react-native-sound';
const MusicApp = () => {
const DATA = [
{
title: 'Advertising Local',
isRequire: true,
url: require('./resource/advertising.mp3'),
},
{
title: 'Advertising URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/advertising.mp3',
},
{
title: 'Hosana',
isRequire: true,
url: require('./Hosana.mp3'),
},
{
title: 'Play aac sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/pew2.aac',
},
{
title: 'Frog wav sound from Local',
isRequire: true,
url: require('./resource/frog.wav'),
},
{
title: 'Frog wav sound from remote URL',
url:
'https://raw.githubusercontent.com/zmxv/react-native-sound-demo/master/frog.wav',
},
];
let sound;
const playSound =(item, id)=>{
console.log("the url is "+ item.url);
if(item.url !=1){
sound = new Sound(item.url, '', (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}else{
sound = new Sound(item.url, (error, _sound) => {
if (error) {
alert('error' + error.message);
return;
}
stopSound
sound.play(() => {
sound.release();
});
});
}
}
const stopSound =(index)=>{
sound.stop(() => {
console.log('Stop');
});
}
const renderItem = ({ item, index }) => (
<ScrollView style={{flex: 1}}>
<View style={styles.item}>
<Text style={styles.title}> {item.title} </Text>
<TouchableOpacity onPress={()=>playSound(item, index)} style={{padding: 10, backgroundColor: 'blue'}}><Text>Play</Text></TouchableOpacity>
<TouchableOpacity onPress={()=>stopSound(index)} style={{padding: 10, backgroundColor: 'red'}}><Text>Stop</Text></TouchableOpacity>
</View>
</ScrollView>
);
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: 20,
},
});
export default MusicApp;
NB:
Do yarn add react-native-sound or npm install react-native-sound.
Secondly, there are two sources of music- Remote url and local file path, ensure you modify the local file path appropriately before running
I am using the following component bottom-sheet, where I am implementing the pull-to-refresh, on android it works perfectly on ios it is not working.
I tried to follow various guides, but I could not figure out what the problem is that on ios it is not working.
Can anyone help me out?
Android ok:
Link: snack
import React, { useCallback, useRef, useMemo, useEffect } from 'react';
import {
StyleSheet,
View,
Text,
Button,
RefreshControl,
ToastAndroid,
Platform,
} from 'react-native';
import BottomSheet, { BottomSheetScrollView } from '#gorhom/bottom-sheet';
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const App = () => {
// hooks
const sheetRef = useRef<BottomSheet>(null);
const [refreshing, setRefreshing] = React.useState(false);
const [listData, setListData] = React.useState([]);
const onRefresh = React.useCallback(async () => {
console.log('Refresh');
setRefreshing(true);
try {
const n = getRandomInt(10, 30);
console.log(n);
let response = await fetch('https://randomuser.me/api/?results=' + n);
let responseJson = await response.json();
setListData(responseJson.results);
setRefreshing(false);
} catch (error) {
console.error(error);
}
}, [refreshing]);
useEffect(() => {
onRefresh();
}, []);
// variables
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
// callbacks
const handleSheetChange = useCallback((index) => {
console.log('handleSheetChange', index);
}, []);
const handleSnapPress = useCallback((index) => {
sheetRef.current?.snapTo(index);
}, []);
const handleClosePress = useCallback(() => {
sheetRef.current?.close();
}, []);
// render
const renderItem = useCallback(
(item) => (
<View key={item.login.uuid} style={styles.itemContainer}>
<Text>{item.email}</Text>
</View>
),
[]
);
return (
<View style={styles.container}>
<BottomSheet
ref={sheetRef}
index={2}
snapPoints={snapPoints}
onChange={handleSheetChange}
enableContentPanningGesture={false}
enableHandlePanningGesture={false}>
<BottomSheetScrollView
contentContainerStyle={{
backgroundColor: 'white',
//paddingTop: Platform.OS === 'ios' ? 0 : 64,
}}
contentInset={{ top: 64 }}
contentOffset={{ x: 0, y: -64 }}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
progressViewOffset={64}
colors={['#000']}
tintColor={'#000'}
/>
}>
{listData.map(renderItem)}
</BottomSheetScrollView>
</BottomSheet>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 200,
},
contentContainer: {
backgroundColor: 'white',
},
itemContainer: {
padding: 6,
margin: 6,
backgroundColor: '#eee',
},
});
export default App;
Im working on a cookie clicker type game and Im working on making features like automatic clickers / combo multipliers. I created the start of the game but when I use my auto function it begins bugging after multiple clicks of the clicker. I have linked the code and an example of the bug occurring below.
CODE
import React, { useState, useEffect } from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import { cases } from "./cases";
import { motion } from "framer-motion";
const io = require("socket.io-client");
const SocketEndpoint = "http://localhost:3000/";
const App = () => {
const [cash, setCash] = useState(0);
const [clicks, setClicks] = useState(0);
const [bot, setBot] = useState(0);
const [open, setOpen] = useState(false);
const [prize, setPrize] = useState(null);
const [connected, setConnected] = useState(false);
const [upgrades, setUpgrades] = useState({auto: false, multi: false})
const [multi, setMulti] = useState(1);
let applied = false;
useEffect(() => {[![enter image description here][1]][1]
const socket = io(SocketEndpoint, {
transports: ["websocket"],
});
socket.on("connect", () => {
setConnected(true)
});
}, [])
useEffect(() => {
if(!applied) {
autoUpgrade();
applied = true;
}
}, [bot, upgrades])
const autoUpgrade = () => {
if (!upgrades.auto) {
return;
}
const inter = setInterval(() => setBot(bot + 1), 1000);
return () => clearInterval(inter);
}
const collectBotIncome = () => {
setCash(cash + bot);
setBot(0);
}
const addMulti = () => {
if (!upgrades.multi) {
return;
}
setMulti(2)
}
const increasePoint = () => {
setClicks(clicks + (1 * multi))
}
const purchaseCase = () => {
setClicks(clicks - 10)
}
const purchaseUpgrade = (upgrade) => {
alert('purchased')
upgrade === 'auto' ? setUpgrades({...upgrades, auto: true}) : null;
upgrade === 'multi' ? setUpgrades({...upgrades, multi: true}) : null;
}
const between = (x, min, max) => {
return x >= min && x <= max;
}
const openCase = () => {
setOpen(true);
purchaseCase();
const ticket = Math.floor(Math.random() * 10000);
console.log('[ROUND] Ticket:' + ticket)
var found = false;
var i;
for (i = 0; i < cases.types[0].items.length; i++) {
var item = cases.types[0].items[i];
if(between(ticket, item.ticketStart, item.ticketEnd)) {
setPrize(item.name)
found = true;
}
}
}
return (
<View style={styles.container}>
<View style={styles.shopMenu}>
<Text style={{color: 'white'}}>Shop</Text>
<Text onClick={() => purchaseUpgrade('auto')} style={{color: 'white'}}>Auto Click Level 1</Text>
<Text onClick={() => purchaseUpgrade('multi')} style={{color: 'white'}}>Click Multiplier Level 1</Text>
</View>
<View style={styles.shopMenu}>
<Text style={{color: 'white'}}>Inventory</Text>
{upgrades.auto
?
<>
<Text style={{color: 'white'}}>{bot}</Text>
<Text onClick={collectBotIncome} style={{color: 'white'}}>Collect Bot Income</Text>
</>
: null
}
</View>
<motion.img
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.9 }}
onClick={increasePoint}
src={require('./src/assets/case.png')} alt="case"
/>
<Text style={{color: 'white'}}>clicks: {clicks ? clicks : "0"}</Text>
<Text style={{color: 'white'}}>connected: {connected ? "true" : "false"}</Text>
{open
? <Text style={{color: 'white'}}>{prize ? prize : 'Failed to get Prize'}</Text>
: <Image
style={clicks >= 10 ? styles.available : styles.unavailable}
source={require('./src/assets/case.png')} alt="case"
onClick={openCase}
/>
}
<Text style={{color: 'white'}}>{cases.types[0].name}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "black",
alignItems: "center",
justifyContent: "center",
},
available: {
display: 'flex',
width: 150,
height: 100,
filter: 'none',
transition: '200ms ease',
marginTop: 50
},
unavailable: {
display: "flex",
width: 150,
height: 100,
filter: 'grayscale(1)',
transition: '200ms ease',
marginTop: 50
},
shopMenu: {
display: "flex",
flexDirection: "column"
}
});
export default App;
PREVIEW
Im using react native and hooks to make a view where i choose from taking a photo with my camera or open my cellphone gallery and chose any image i want, once i have a picture it should show the image in a list, so if i choose more than one picture it should show more than oneimage in the list.
const Seleccion = ({navigation}) => {
const [fileList, setFileList] = useState([]);
const state = useMemo(() => ({ fileList }), [fileList]);
const onSelectedImage = useCallback((image) => {
setFileList(fileList => {
const newDataImg = [...fileList];
const source = { uri: image.path };
const item = {
id: Date.now(),
url: source,
content: image.data
};
newDataImg.push(item);
return newDataImg;
});
}, [setFileList]);
const takePhotoFromCamera = useCallback(() => {
ImagePicker.openCamera({
width: 300,
height: 400,
}).then(image => {
onSelectedImage(image);
console.log(image);
});
}, [onSelectedImage]);
const choosePhotoFromLibrary = useCallback(() => {
ImagePicker.openPicker({
width: 300,
height: 400,
}).then(image => {
onSelectedImage(image);
console.log(image);
});
}, [onSelectedImage]);
const renderItem = useCallback(({ item, index }) => {
return (
<View>
<Image source={item.url} style={styles.itemImage} />
</View>
);
}, []);
return (
<View style={styles.container}>
<FlatList
data={fileList}
keyExtractor={(item, index) => index.toString()}
renderItem={renderItem}
extraData={state}
/>
<TouchableOpacity style={styles.viewData} onPress={takePhotoFromCamera}>
<Text>Foto</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.viewData} onPress={choosePhotoFromLibrary}>
<Text>galeria</Text>
</TouchableOpacity>
</View>
);
}
This was my dirty component in a sample, take a look at it:
import React, {useState, useEffect, Fragment} from 'react';
import Icon from 'react-native-vector-icons/FontAwesome5Pro';
import {
View,
Modal,
ScrollView,
Image,
TouchableOpacity,
Text,
} from 'react-native';
import ActionSheet from 'react-native-action-sheet';
import ImagePicker from 'react-native-image-crop-picker';
import ImageViewer from 'react-native-image-zoom-viewer';
import styles from '../../../../../../styles';
const BUTTONS = ['Gallery', 'Camera', 'Cancel'];
export default props => {
let {files, setFiles} = props;
const [ImageViwerIsVisible, showImageViwer] = useState(false);
let [viewingIndex, setViewingIndex] = useState(-1);
useEffect(() => {
viewingIndex !== -1 && showImageViwer(true);
}, [viewingIndex]);
useEffect(() => {
!ImageViwerIsVisible && setViewingIndex(-1);
}, [ImageViwerIsVisible]);
const showActionSheet = () =>
ActionSheet.showActionSheetWithOptions(
{
title: 'Choose photo location',
options: BUTTONS,
cancelButtonIndex: 2,
destructiveButtonIndex: 2,
tintColor: 'blue',
},
buttonIndex => {
switch (buttonIndex) {
case 0:
return selectFromGallery();
case 1:
return selectFromCamera();
default:
return 0;
}
},
);
const selectFromGallery = () =>
ImagePicker.openPicker({
multiple: true,
//cropping: true,
})
.then(image => {
setFiles([...files, image].flat());
})
.catch(e => {});
const selectFromCamera = () =>
ImagePicker.openCamera({
cropping: true,
includeExif: true,
})
.then(image => {
setFiles([...files, image]);
})
.catch(e => {});
return (
<Fragment>
{!!ImageViwerIsVisible && (
<Modal transparent={true} onRequestClose={() => showImageViwer(false)}>
<ImageViewer
imageUrls={files.map(f => ({url: f.path}))}
index={viewingIndex}
/>
</Modal>
)}
<View
style={{
flexDirection: 'row',
padding: 10,
backgroundColor: '#ececec',
marginBottom: 5,
}}>
<TouchableOpacity onPress={() => showActionSheet()}>
<Icon solid name="camera-retro" size={32} />
</TouchableOpacity>
{/* <Text>{JSON.stringify(files, null, 2)}</Text> */}
<ScrollView style={{flexDirection: 'row', flex: 1}} horizontal>
{files.map((file, index) => (
<TouchableOpacity
key={file.path}
onPress={() => setViewingIndex(index)}
onLongPress={() =>
ImagePicker.cleanSingle(file.path)
.then(() => setFiles(files.filter(f => f.path !== file.path)))
.catch(e => {})
}
style={{
marginRight: 5,
width: 50,
height: 50,
borderWidth: 1,
borderColor: '#000',
borderRadius: 5,
}}>
<Image
source={{uri: file.path}}
style={{width: '100%', height: '100%', borderRadius: 5}}
/>
</TouchableOpacity>
))}
</ScrollView>
</View>
</Fragment>
);
};
You need to place useCallBack as you were use in your code, in that time i was dummy about react-hooks.