How to map over axios array to display image - reactjs

I want to display an image from my data. It works when I use Flatlist but Flatlist has conflicts with ScrollView, so I had to change my displaying method from Flatlist to mapping with component.
First name renders when I use {profile.first_name}, but the image won't render. I believe the issue is in the source = {} of the Image. I have tried profile.banner_picture and that has not worked either.
const bannerPicture = () => {
return profile.map((profile) => {
return (
<View key={profile.key}
style={{padding: 1}}>
<Image
source={banner_picture}
style = {{
height: 100,
width: 100,
}}/>
<Text>{profile.first_name}</Text>
</View>
);
});
};

When I change
source = {banner_picture}
//to this
source={{uri: banner_picture}}
// it works
const bannerPicture = () => {
return profile.map((profile) => {
return (
<View key={profile.key}
style={{
flex: 1,
height: 400,
width: 400,
padding: 1}}>
<Image
source={{uri: banner_picture}}
style = {{
height: 100,
width: 100,
}}/>
<Text>{profile.first_name}</Text>
</View>
);
});
};

Related

ScrollView Getting error undefined is not a function, js engine: hermes

I Tried to using useRef to automate scroll if I press button
The idea is scroll with my scrollview and then I can press button to scroll to another set of view in my scrollview
this is my complete slider code
import { height } from 'deprecated-react-native-prop-types/DeprecatedImagePropType'
import { onChange } from 'deprecated-react-native-prop-types/DeprecatedTextInputPropTypes'
import React , {useState,useRef} from 'react'
import { StyleSheet, View , Text , ScrollView , Pressable , Image, Dimensions , TouchableOpacity} from 'react-native'
const WIDTH = Dimensions.get('window').width
const HEIGHT = Dimensions.get('window').height
const ImageSlider = ({slides}) => {
const refScrollview = useRef()
const [currentIndex,setCurrentIndex] = useState(0)
// console.log(slides[currentIndex].banner)
const [imageActive,setImageActive] = useState(1)
const onChange = (nativeEvent) =>{
if(nativeEvent){
const slide = Math.ceil(nativeEvent.contentOffset.x / nativeEvent.layoutMeasurement.width)
if(slide != imageActive){
console.log(slide)
setImageActive(slide)
console.log(refScrollview.current)
}
}
}
return(
<View style={{flex:1}}>
<ScrollView
ref={refScrollview}
// onContentSizeChange={(contentWidth, contentHeight)=> {refScrollview.current.scrollToEnd({animated: true})}}
onScroll={({nativeEvent}) => onChange(nativeEvent)}
showsHorizontalScrollIndicator={false}
pagingEnabled
horizontal
style={styles.wrap}
>
{
slides.map((e,index)=>
// <Text>{e.banner}</Text>
<View style={{flex:1}} key={index}>
<Image source={e.banner}
style={[styles.wrap]}
>
</Image>
<Image source={e.bannerFace}
style={styles.bannerFace}
>
</Image>
</View>
)
}
</ScrollView>
<View style={styles.wrapDot}>
{
slides.map((e,index)=>
<TouchableOpacity key={index} style={imageActive == index ? styles.lineActive : styles.lineOnly} onPress={() => {
refScrollview.current.scrollTo()}}>
</TouchableOpacity>
)
}
</View>
</View>
)
}
let styles = StyleSheet.create({
backgroundImage: {
flex:1,
width: null,
height: null,
// width: 400,
// height: 400,
// resizeMode: 'cover',
},
bannerFace:{
position:'absolute',
bottom:0,
right:0,
flex: 1,
width: 150,
height: 150,
resizeMode: 'contain'
},
wrap:{
width:WIDTH,
height:'100%'
},
wrapDot:{
position:'absolute',
bottom:20,
left:50,
flexDirection:'row',
alignSelf:'center'
},
lineOnly:{
padding:5,
width:70,
borderRadius:15,
borderColor:'#CECECE',
backgroundColor:'#CECECE',
marginHorizontal:5
},
lineActive:{
padding:5,
width:70,
borderRadius:15,
borderColor:'#FFF',
backgroundColor:'#FFF',
marginHorizontal:5
}
})
export default ImageSlider
I get the error TypeError: undefined is not a function, js engine: hermes
whenever i try to push/use this
onPress={() => {
refScrollview.current.scrollTo()}}
It looks like there is no scrollTo() function , am I doing this wrong ? or is it my react node.modules ?

Conditional rendering cannot be seen due to a return before them

Please help give me a better title, I couldn't word what I am asking.
To understand my question I have to provide some context of my project. Originally I wanted to conditionally render two pages through two buttons. Button A rendering screen A and button B rendering screen B. After figuring out how to pass the state from a parent component to a child and its child etc, I changed my button to a sliding animation for better design.
This causes issues because now when a new screen is rendered, the animation does not show because it is simply re-rendered with the original starting place in the animation(I rendered the slider through each screen). I thought about providing two different sliders, each starting in the opposing opposition but that would still lose the entire slide effect.
I have now resulted to rendering the Slider so it is there all the time and is not re-rendered. However I have realized now that if I return it before my conditionals, that code is never reached. I have provided a working demo that shows my problem perfectly as well as the code below(I only provided App.js, the rest is on the demo if needed). I want to render Slider in App.js.
The working demo is here, you can see the slider does not slide, it just changes screens. I need it to slide. Also the sliding animation only works on iphone so I would use that emulator rather than the web.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
whichComponentToShow: "Screen1"
};
}
goToMap = () => {
this.setState({ whichComponentToShow: "Screen2" });
};
goToList = () => {
this.setState({ whichComponentToShow: "Screen1" });
};
render() {
const { whichComponentToShow } = this.state;
/* This is how I thought I could render this, but obv it makes the rest of the code unreachable.
How can I render this and then have the conditional page below? Each time the new page renders,
it stops the animation from working due to rendering the new page.
return(
<Slider/>
)*/
if(this.state.whichComponentToShow === 'Screen1'){
return(
<View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
<ListHome
renderMap = {this.goToMap.bind(this)}
renderList = {this.goToList.bind(this)}
/>
</View>
);
}
else if(this.state.whichComponentToShow === 'Screen2'){
return(
<View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
<MapHome
renderMap = {this.goToMap.bind(this)}
renderList = {this.goToList.bind(this)}
/>
</View>
);
}
Slider.js (wont show up on the snack apparently
const Slider = (props) => {
const [active, setActive] = useState(false)
let transformX = useRef(new Animated.Value(0)).current;
useEffect(() => {
if (active) {
Animated.timing(transformX, {
toValue: 1,
duration: 300,
useNativeDriver: true
}).start()
} else {
Animated.timing(transformX, {
toValue: 0,
duration: 300,
useNativeDriver: true
}).start()
}
}, [active]);
const rotationX = transformX.interpolate({
inputRange: [0, 1],
outputRange: [2, Dimensions.get('screen').width / 4]
})
return (
<SafeAreaView style={{
flex: 1,
alignItems: 'center'
}}>
<View style={{
flexDirection: 'row',
position: 'relative',
height: 45,
width: 240,
borderRadius: 10,
backgroundColor: 'white',
marginHorizontal: 5
}}>
<Animated.View
style={{
position: 'absolute',
height: 45 - 2*2,
top: 2,
bottom: 2,
borderRadius: 10,
width: Dimensions
.get('screen').width / 3 - 3.5 ,
transform: [
{
translateX: rotationX
}
],
backgroundColor: '#d1cfcf',
}}
>
</Animated.View>
<TouchableOpacity style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}} onPress={() => {setActive(false); props.renderList() }}>
<Text>
List
</Text>
</TouchableOpacity>
<TouchableOpacity style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}} onPress={() => {setActive(true); props.renderMap() }}>
<Text>
Map
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
}
export default Slider
I tried your expo snack and saw no code related to animation, so I'm assuming the code in the snack isn't your current code, and that you really do already have a working, animated, <Slider ... />.
In your situation, what you could do to keep your Slider rendered and not unmounted, is to use variables in the render() method.
Basically, you can assign the <Slider .../> JSX to a variable, and you can use that variable in another JSX part later.
Assigning a key to the specific JSX also helps guide React that this is the same component between render calls, so it also prevents unintentional rerenders of that component.
Here's an edit with comments from what you wrote in your post. I hope this makes sense.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
whichComponentToShow: "Screen1"
};
}
goToMap = () => {
this.setState({ whichComponentToShow: "Screen2" });
};
goToList = () => {
this.setState({ whichComponentToShow: "Screen1" });
};
render() {
const { whichComponentToShow } = this.state;
/*
Keep the slider JSX in a variable to be used.
Setting a specific key also helps prevent it from being accidentally re-rendered in some conditions.
)*/
const sliderRender = <Slider key='slider' />;
if (this.state.whichComponentToShow === 'Screen1') {
return (
<View style={{ backgroundColor: '#d1cfcf', flex: 1 }}>
<ListHome
renderMap={this.goToMap.bind(this)}
renderList={this.goToList.bind(this)}
/>
{/* Put the rendered slider into the render tree */}
{sliderRender}
</View>
);
}
else if (this.state.whichComponentToShow === 'Screen2') {
return (
<View style={{ backgroundColor: '#d1cfcf', flex: 1 }}>
<MapHome
renderMap={this.goToMap.bind(this)}
renderList={this.goToList.bind(this)}
/>
{/* Put the rendered slider into the render tree */}
{sliderRender}
</View>
);
}
}
}
Edit : Expo Snack demonstrating it working

react native - Image not showing on custom callout in mapview?

I have a map screen with markers, I try to add image to the callout and I use same method of <image source = .. /> as I did in other place that works, but on the map it wont show me the picture.
{
this.state.markers.map(marker => (
<MapView.Marker
key={marker.id}
coordinate={{longitude: marker.longitude, latitude: marker.latitude}}>
<MapView.Callout>
<View>
<View>
{marker.imageUri && <Image source = {{uri: marker.imageUri}}
style = {{ width: '90%', height: 100, justifyContent: 'center', flex: 1, alignContent: 'center', resizeMode: 'stretch'}}
/> }
</View>
<Text>Lat: {marker.latitude}, Lon: {marker.longitude}</Text>
<Text>{marker.email}</Text>
</View>
</MapView.Callout>
</MapView.Marker>
))
}
it gives me a blank view instead of the image.
Have I done any mistake?
Use Image inside Text component,It is strange but it works :)
<Text> <Image style={{ height: 100, width:100 }} source={{ ... }} resizeMode="cover" /> </Text>
https://docs.expo.io/versions/latest/sdk/webview/
import { WebView } from 'react-native-webview';
If const isAndroid = Platform.OS === 'android'; is true render a WebView... if not render a Image.
I fixed it by using a webView for android: const Img = isAndroid ? WebView: Image; return <Img source={{uri: someUri}} />

API image not being displayed in list

I know there are several questions with this issue but mine is different.
I trying to display an image in my Flatlist card that is coming from an API. However it is not showing up.
BUT...when I display this image in another part of my code (in an Autocomplete list) using the same code basically, it works. Also, when I try an url from an image on the Web, it displays inside the flatlist correctly
Here's my Flatlist code:
<FlatList
data={this.state.myGamesArray}
renderItem={({ item }) => (
<Card>
<CardItem>
<View>
<Image
style={styles.gameImage}
source={{uri: item.background_image}}
/>
</View>
</CardItem>
<CardItem>
<View>
<Text style={styles.usergameText}>
{item}
</Text>
</View>
</CardItem>
</Card>
)}
keyExtractor={(item,index) => index.toString()}
/>
Here is my Autocomplete code in which I use the same image bracket-thingy
<View style={styles.iconContainer} >
<TouchableOpacity onPress={() => this.setState({ query: item.name})}
style={styles.autocompleteList} >
<View>
<Image
style={styles.gameImage}
source={{uri: item.background_image}}
/>
</View>
<Text style={styles.gameText}>
{item.name}
</Text>
</TouchableOpacity>
</View>
I ran console.item(item.background_image) both inside the Flatlist(first snippet) and the Autocomplete list (Second snippet). The first shows 'undefined' and the second it shows all the URIs
App.js full code:
/*This is an example of AutoComplete Input/ AutoSuggestion Input*/
import React, { Component } from 'react';
//import react in our code.
import { StyleSheet, Text, TouchableOpacity, View, Image, FlatList, Alert, TouchableWithoutFeedback, Keyboard } from 'react-native';
//import all the components we are going to use.
import Autocomplete from 'react-native-autocomplete-input';
import { Button, List, Container, ListItem, Card, CardItem, Header, Item } from 'native-base';
import { Entypo } from '#expo/vector-icons'
//import Autocomplete component
//const API = 'https://api.rawg.io/api/games?page=1';
//Demo base API to get the data for the Autocomplete suggestion
class App extends Component {
constructor(props) {
super(props);
//Initialization of state
//films will contain the array of suggestion
//query will have the input from the autocomplete input
this.state = {
myGamesArray: [],
games: [],
query: ' ',
};
}
componentDidMount() {
//First method to be called after components mount
//fetch the data from the server for the suggestion
fetch('https://api.rawg.io/api/games?page=1&platforms=18', {
"method": "GET",
"headers": {
"x-rapidapi-host": "rawg-video-games-database.p.rapidapi.com",
"x-rapidapi-key": "495a18eab9msh50938d62f12fc40p1a3b83jsnac8ffeb4469f"
}
})
.then(res => res.json())
.then(json => {
const { results: games } = json;
this.setState({ games });
//setting the data in the games state
});
}
findGame(query) {
let i;
//method called everytime when we change the value of the input
if (query === '') {
//if the query is null then return blank
return [];
}
const { games } = this.state;
//making a case insensitive regular expression to get similar value from the film json
const regex = new RegExp(`${query.trim()}`, 'i');
//return the filtered game array according the query from the input
return games.filter(game => game.name.search(regex) >= 0);
}
AddItemsToArray = () => {
var i
//verifica se input esta vazio
if (this.state.query === '') {
return Alert.alert('Voce não selecionou um jogo')
}
//VERIFY IF GAME IS IN THE ARRAY
for (i = 0; i < this.state.games.length - 1; i++) {
if (this.state.query !== this.state.games[i].name) {
if (i === this.state.games.length - 2) {
return Alert.alert('Este jogo nao existe')
}
else {
continue
}
} else {
break
}
}
//verifica repetido
if (this.state.myGamesArray.includes(this.state.query)) {
return Alert.alert('Este jogo já foi adicionado')
}
else {
//Adding Items To Array.
this.setState(prevState => {
const { myGamesArray, query } = prevState;
return {
myGamesArray: [...myGamesArray, query.toString()],
};
},
// Use setState callback to alert with the updated state
);
}
}
render() {
const { query } = this.state;
const games = this.findGame(query);
const comp = (a, b) => a.toLowerCase().trim() === b.toLowerCase().trim();
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss()
}}
>
<View style={styles.container}>
<View style={styles.listContainer}
>
<FlatList
data={this.state.myGamesArray}
renderItem={({ item }) => (
console.log(item.background_image),
<Card style={{flexDirection:'row',paddingEnd:100}}>
<CardItem cardBody>
<View>
<Image
style={styles.listImage}
source={{uri: item.background_image}}
/>
</View>
</CardItem>
<CardItem>
<View>
<Text style={styles.usergameText}>
{item}
</Text>
<Text style={styles.usergameText}>
Playstation 4
</Text>
</View>
</CardItem>
</Card>
)}
keyExtractor={(item,index) => index.toString()}
/>
</View>
<View>
<Header span
style={styles.header}>
<Autocomplete
inputContainerStyle={{borderColor:'transparent'}}
style={styles.autocompleteInput}
autoCapitalize="none"
autoCorrect={false}
//data to show in suggestion
data={games.length === 1 && comp(query, games[0].name) ? [] : games}
//default value if you want to set something in input
defaultValue={query}
/*onchange of the text changing the state of the query which will trigger
the findGame method to show the suggestions*/
onChangeText={text => this.setState({ query: text })}
placeholder=" Adicione os jogos que você tem"
//This below is the 'list' of autocomplete options
renderItem={({ item }) => (
//you can change the view you want to show in suggestion from here
//I GET ERROR WHEN TRYING TO ERASE (PS4) IN TEXT BOX ***NEED TO CHECK THIS
<View style={styles.iconContainer} >
<TouchableOpacity onPress={() => this.setState({ query: item.name})}
style={styles.autocompleteList} >
<View>
<Image
style={styles.gameImage}
source={{uri: item.background_image}}
/>
</View>
<Text style={styles.gameText}>
`${item.name}`
</Text>
</TouchableOpacity>
</View>
)}
/>
</Header>
</View>
<TouchableOpacity
style={styles.addButton}
onPress={() => this.AddItemsToArray()}
>
<Entypo name="plus" size={50} color="#fff" />
</TouchableOpacity>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#fff',
flex: 1,
},
autocompleteInput: {
borderWidth: 1,
backgroundColor: "#fff",
borderColor: '#7843FF',
height: 50,
marginTop: 70,
borderRadius:10,
},
autocompleteList: {
flex:1,
flexDirection: 'row',
borderWidth:0.5,
borderColor: '#7843FF',
paddingVertical: 5,
paddingRight: 60,
},
listContainer: {
flex: 1,
position: 'absolute',
left: 10,
right: 10,
top:150,
flexDirection:'column',
justifyContent: 'center',
borderColor: '#7843FF',
},
gameText: {
fontSize: 15,
marginLeft: 10,
marginRight:30,
marginVertical:10,
color: '#000',
textAlign: 'left',
justifyContent: 'center'
},
usergameText: {
fontSize:15,
textAlign: 'left',
alignSelf:'stretch',
color: '#000',
},
gameImage: {
flex: 3,
height: 60,
width: 60,
marginLeft:10,
borderRadius: 100,
},
listImage: {
flex: 3,
height: 110,
width: 90,
marginLeft:0,
},
addButton: {
height:50,
width: 50,
position: 'absolute',
left: 371,
top: 71,
backgroundColor: '#7843FF',
borderTopRightRadius: 10,
borderBottomRightRadius:10,
},
usergameImage: {
height: 100,
width: 100,
borderRadius: 100,
},
header: {
backgroundColor:'#67E6DC'
}
});
export default App;

Multiple onPress event on a single image component in React Native

I have this picture, and I want to have multiple onPress event for this image.
Example if I touch the head part it will call the function pressHead() and if I touch the chest part it will call the function pressChest().
So far I have tried plotting checkboxes on each part.
import React, { Component } from 'react';
import { View, Image, Alert } from 'react-native';
import { CheckBox } from 'react-native-elements';
export default class Screen extends Component {
pressHead() {
this.setState({checked1: !this.state.checked1})
Alert.alert('Pressed Head', '');
}
pressChest() {
this.setState({checked2: !this.state.checked2})
Alert.alert('Pressed Chest', '');
}
render() {
return (
<View style={{width: 200}}>
<Image
style={{width: 200, resizeMode: 'contain'}}
source={require('../../assets/images/body-diagram.png')}
/>
<CheckBox
containerStyle={{position: 'absolute', top: 22, right: 75, padding: 0}}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='#ff0000'
checked={this.state.checked1}
onPress={() => this.pressHead()}
/>
<CheckBox
containerStyle={{position: 'absolute', top: 70, right: 75, padding: 0}}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='#ff0000'
checked={this.state.checked1}
onPress={() => this.pressChest()}
/>
</View>
);
}
}
This does work. But if I try to use it on a larger device, the position absolute becomes not accurate enough.
Give the constant height for the image and overlay the checkboxes as same above respect to image. Since height is also made constant you don't find any position issues of the checkbox in any screen.
Example :
<View style={{width: 200, height: 600}}>
<Image
style={{width: 200, height: 600 ,resizeMode: 'contain'}}
source={require('../../assets/images/body-diagram.png')}
/>
You can do it by changing your image to <ImageBackground .. /> component after importing it from react-native.
After doing that you can place Touchable things inside of ImageBackground.
Example:
<ImageBackground source={require('../../assets/images/body-diagram.png')} style={{width: 200, height: 600, flexDirection: 'column'}}
<TouchableOpacity onPress={() => alert('first pressed')}>
<Text>First Area</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('second pressed')}>
<Text>Second Area</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('third pressed')}>
<Text>Third Area</Text>
</TouchableOpacity>
<ImageBackground/>

Resources