url path with image variable in image source uri React Native - react-native

I am trying to display an Image in which the data was fetch from an api and render into a flatlist, I am trying to concat or connect the sting link with the variable, in the image source uri but did not work, how can I fix it.
<FlatList
data = {data}
keyExtractor={item => item.id}
showsVerticalScrollIndicator = {false}
renderItem={({item}) => {
return (
<Image
source={{ uri: `https://placewave.com/avatar/${item.user_image}` }}
resizeMode="cover"
style={styles.userImage}
/>
)
}}
/>
Thanks for the help

Unfortunately it will not work in such way.
Image must not have conditional source prop. Consider moving https://placewave.com/avatar/${item.user_image} to a variable and add condition to display some kind of fallback(like ActivityIndicator) until you will have valid user_image.

Complete test code
import * as React from 'react';
import { Image, Text, View, StyleSheet, FlatList } from 'react-native';
import Constants from 'expo-constants';
export default function App() {
const data = [{ id: 1, user_image: 'cute-boy-standing-little-white-background-40214306.jpg' }, { id: 1, user_image: 'no image url.jpg' }]
return (
<View >
<FlatList
data={data}
keyExtractor={item => item.id}
showsVerticalScrollIndicator={false}
renderItem={({ item }) => {
let uriVar
if (item.user_image) uriVar = `https://thumbs.dreamstime.com/b/${item.user_image}`
return (<View>
{uriVar != null ?
<Image source={{ uri: uriVar }}
style={styles.userImage}
/> : null} </View>)
}}
/>
<Text style={styles.paragraph}>
Hello
</Text>
</View>
);
}
const styles = StyleSheet.create({
userImage: {
width: '150px',
height: '150px',
borderWidth: 1
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});

Thank you all for the respond, but I find the answer
First I define the url const URL = 'https://placewave.com/avatar';
Then Include it:
<Image
source={{ uri: URL + '/' + item.user_image}}
resizeMode="cover"
style={styles.userImage}
/>

Related

React Native Flatlist Video custom Fullscreen

Has anyone here ever done a vertical video Flatlist with a button that makes the video fullscreen (not the native UI). If yes could you give some advice on how to achieve it? Should I make the video position absolute and make it go from top to bottom (tried but couldn't make it work in the Flatlist)? Should I have a hidden video component that shares the state with the one in the Flatlist? Thanks any guidance is appreciated
I would recommend using modal feature from react navigation package(check this)
with this package you can render your full screen video inside a separate view.
Here you go.
const App: () => Node = () => {
const [popup, setPopup] = useState(false);
return (
<View style={{flex: 1, backgroundColor: 'aliceblue'}}>
<FlatList
data={[
{title: '1', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
{title: '2', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
]}
renderItem={({item}) => (
<Button title={item.title} onPress={() => setPopup(true)} />
)}
/>
{popup ? (
<View
style={{
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
backgroundColor: '#00000050',
}}>
<View
style={{
backgroundColor: '#FFFFFF50',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>Use whatever library you want to use to play the video</Text>
</View>
<Button title="Close" onPress={() => setPopup(false)} />
</View>
) : null}
</View>
);
};
I've built a sample that works for your requirement. Didn't do the Video stuff tho. Hope this helps.
Updated code with Popup component
const Popup = ({videoUrl, onClose}) => {
return (
<View
style={{
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
backgroundColor: '#00000050',
}}>
<View
style={{
backgroundColor: '#FFFFFF50',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>{videoUrl}</Text>
</View>
<Button title="Close" onPress={onClose} />
</View>
);
};
const App: () => Node = () => {
const [popup, setPopup] = useState(null);
return (
<View style={{flex: 1, backgroundColor: 'aliceblue'}}>
<FlatList
data={[
{title: '1', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
{title: '2', url: 'https://www.w3schools.com/html/mov_bbb.mp4'},
]}
renderItem={({item}) => (
<Button
title={item.title}
onPress={() =>
setPopup({
videoUrl: item.url,
})
}
/>
)}
/>
{popup != null ? (
<Popup videoUrl={popup.videoUrl} onClose={() => this.setPopup(null)} />
) : null}
</View>
);
};
What is exact problem? You can't make it fullscreen by custom button? Or you want to make it fullscreen with your own custom layout? I guess first.
Not clean example, but should show how it works.
https://snack.expo.dev/#valera.bitkovsky/react-native-flatlist-video-custom-fullscreen
import React from "react";
import { StyleSheet, Text, View, FlatList, Button } from "react-native";
import { Video, AVPlaybackStatus } from 'expo-av';
const VideoItem = React.forwardRef(({ url }, ref) => {
const video = React.useRef(null);
React.useImperativeHandle(ref, () => ({
full: () => {
video.current.presentFullscreenPlayer();
}
}), [])
return <Video
ref={video}
source={{
uri: url,
}}
style={{
width: 400,
height: 200
}}
useNativeControls
resizeMode="contain"
isLooping
/>
});
function App() {
const videoRefs = React.useRef([]);
return (
<View style={styles.app}>
<FlatList
data={[
{ url: "https://www.w3schools.com/html/mov_bbb.mp4" },
{ url: "https://www.w3schools.com/html/mov_bbb.mp4" }
]}
renderItem={({ item, index }) => (<View>
<VideoItem ref={ref => videoRefs.current[index] = ref} url={item.url} />
<Button title="Fullscreen" onPress={() => videoRefs.current[index].full()} />
</View>)}
/>
</View>
);
}
const styles = StyleSheet.create({
app: {
marginTop: 50,
marginHorizontal: "auto",
maxWidth: 500
}
});
export default App;
And if you want second varint, then you can just add state and change layout to absolute and do whatever you want.
UPD
Regarding the aproach where we use absolute styles, seems that isn't possible, see this issue
https://github.com/facebook/react-native/issues/29867
So, we still can use our custom controls, but probably we should use native fullscreen mode.
You can try use simple ScrollView, I know that it isn't optimazied for that very well, but absolute position should work

How can use useState() with Flatlist data?

I've had a problem when i used useState(). i have to filter by searched words on my data and list.
i need to define my data list with State (i'd list with searched words) but when i use State, i've taken 'Invalid Hook' error.
let [list, setList] = useState(data);
//called
data={list}
I don't find where i use that , I couldn't fix for 3 days, i can't reach next step :( I hope i'll fix with expert helps...
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
export default class Flatlistexample extends Component {
render () {
//defined below
let [list, setList] = useState(data);
seachFilter=(text)=>{
const newData = data.filter(item=>{
const listitem= `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//called
data={list}
renderItem={({item, index})=>{
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
const [search, setSearch] = useState('');
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text=>{
setSearch(text)
}}
></TextInput>
</View>
)
}}
/>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
Thank you
React hooks can be used with functional component only, here you are using class component
You need to understand the difference between functional component and class component first.
Here you are using class component so your state should be manageed in the following way
export default class Flatlistexample extends Component {
constructor(props)
{
this.state={list:[]}
}
}
and to update list
this.setState({list: <array of data>})
If you want to use hooks, your component needs to be changed something like the following:
const Flatlistexample = () => {
//defined below
let [list, setList] = useState(data);
seachFilter = (text) => {
const newData = data.filter(item => {
const listitem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList data={list} renderItem={Your flatlist Item}/>
</SafeAreaView>
)
}
export default Flatlistexample
Here you go, I've added lots of comments. I hope you find this instructive. Let me know if you have questions!
import React, { useMemo, useState } from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
// changed this to a functional component so you can use hooks. You can't use hooks in class components.
const Flatlistexample = () => {
// you don't actually need to `useState` for your list, since you're always just filtering `data`
// you would need to use `useState` if you were receiving data from an API request, but here it's static
const [search, setSearch] = useState('') // this should live in the main component so you can filter the list
const parsedSearch = search.toLowerCase() // do this once outside the filter, otherwise you're converting it for each item in the data array
const filteredList = useMemo(
() =>
data.filter(item => {
const itemText = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return itemText.indexOf(parsedSearch) > -1 // returns `true` if search is found in string
}),
[parsedSearch], // this will only run if parsedSearch changes
)
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
//called
data={filteredList} // use the filtered list here
renderItem={({ item, index }) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{ backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb' },
]}
>
<Image style={styles.profile} source={{ uri: item.picture }} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
setSearch(text)
}}
/>
</View>
)
}}
/>
</SafeAreaView>
)
}
export default Flatlistexample

React Native mapbox | react-native-mapbox-gl |How to change PointAnnotation Image and Callout is not touchable in Android?

I am trying to change the default Mapbox pin icon on Android as in iOS I'm getting the expected result.
Issue
Not able to change PointAnnotation Icon(Using PNG format)
Callout image is also not loading(Using PNG format)
Not able to click on callout.
All the above issues I'm facing in Android only, iOS is working fine.
import React from 'react';
import {
View,
Image,
} from 'react-native';
import MapboxGL from '#react-native-mapbox-gl/maps';
const currentLatLng = [
[-74.00597, 40.71427]
];
class BugReportExample extends React.Component {
render() {
return (
View style={{flex: 1}}>
<MapboxGL.MapView
ref={c => (this._map = c)}
logoEnabled={false}
style={{flex: 1}}>
<MapboxGL.Camera
ref={c => (this.camera = c)}
zoomLevel={14}
centerCoordinate={currentLatLng}
/>
{/* User location */}
<MapboxGL.PointAnnotation
key={'9090'}
ref={ref => (this.userAnnotationRef = ref)}
id={'9090'}
coordinate={currentLatLng}
title="">
<View style={{ width: 45,height: 45,alignItems: 'center',justifyContent: 'center',overflow: 'hidden',}}>
<Image
source={{uri:'https://reactnative.dev/img/tiny_logo.png'}}
resizeMode={'contain'}
style={{height: wp('10%'), width: wp('10%')}}
onLoad={() => this.userAnnotationRef.refresh()}
/>
</View>
<MapboxGL.Callout title={'You'} />
</MapboxGL.PointAnnotation>
</MapboxGL.MapView>
</View>
);
}
}
This is working fine on iOS.
iOS Result
Android - Issue
const ImageMarker = ({ children }) =>
Platform.select({
ios: children,
android: (
<Text
style= {{
lineHeight: 60, // there is some weird gap, add 40+ pixels
// backgroundColor: '#dcdcde',
}}>
{ children }
< /Text>
),
});
<ImageMarker>
<Image
source={IMAGE_LINK}
style={{width: 45, height: 55}}
/>
</ImageMarker>
Load image before assigning it to the PointAnnotation.
const [imagesLoaded, setImagesLoaded] = useState(false);
setTimeout(() => {
setImagesLoaded(true);
}, 500);
const Example = () => {
render() {
return (
{imagesLoaded ?
// Your mabox code with PointAnnotation
:
<Image
source={{uri:'https://reactnative.dev/img/tiny_logo.png'}}
resizeMode={'contain'}
style={{height: wp('10%'), width: wp('10%'), opacity:0}}
/>
);
}
}

undefined is not an object( evaluating 'state.selected.clip.clip') getting this error using Api in react Native

import React,{useState} from 'react';
import axios from 'axios';
import { Video } from 'expo-av';
import { StyleSheet, View,Text, TextInput, ScrollView, Image, TouchableHighlight, Modal, Button } from 'react-native';
export default function App() {
const apiurl = 'https://api.rawg.io/api/games?page_size=5';
const [state, setState] = useState({
s: 'Enter a movie ...',
results: [],
selected: [],
});
const search = () => {
axios(apiurl + '&search=' + state.s).then(({data}) => {
let results = data.results;
console.log(results);
setState(prevState => {
return {
...prevState,
results: results,
};
});
});
};
const openPopup = slug => {
axios('https://api.rawg.io/api/games/' + slug).then(({data}) => {
let result = data;
console.log(result);
setState(prevState => {
return {...prevState, selected: result};
});
});
};
return (
<View>
<Text> Game Search</Text>
<TextInput
onChangeText={text =>
setState(prevState => {
return {
...prevState,
s: text,
};
})
}
value={state.s}
onSubmitEditing={search}
/>
<ScrollView>
{state.results.slice(0, 1).map(result => (
<TouchableHighlight
key={result.slug}
onPress={() => openPopup(result.slug)}>
<View>
<Image
source={{uri: result.background_image}}
style={{
width: 250,
height: 250,
alignItems: 'center',
justifyContent: 'center',
}}
resizeMode="cover"
/>
<Text>{result.name}</Text>
</View>
</TouchableHighlight>
))}
</ScrollView>
<Modal
animationType="fade"
transparent={false}
visible={typeof state.selected.name != 'undefined'}>
<ScrollView>
<View>
<Text>{state.selected.name}</Text>
<Image
source={{uri: state.selected.background_image}}
style={{
margin: 20,
width: '90%',
height: 300,
alignItems: 'center',
justifyContent: 'center',
}}
resizeMode="cover"
/>
<Video
source={{uri: state.selected.clip.clip}}
rate={1.0}
volume={1.0}
resizeMode="cover"
shouldPlay
isLooping
style={{width: 300, height: 300}}
/>
</View>
</ScrollView>
<Button
onPress={() =>
setState(prevState => {
return {...prevState, selected: {}};
})
}
title="Close"
/>
</Modal>
</View>
);
}
Whenever I run it, it gives me this error message for the clip otherwise don't get an error message for the image or name or anything else. Does anyone know how to solve it? It's a simple app and all the codes are in App.js
Here I have attached the image of the error that I am getting. I am using RawG API to create a simple Game-search app
Screenshot of that error
You need to handle the case where state.selected.clip is null or undefined. You can do that like this:
{
state.selected.clip && (
<Video
source={{uri: state.selected.clip.clip}}
rate={1.0}
volume={1.0}
resizeMode="cover"
shouldPlay
isLooping
style={{width: 300, height: 300}}
/>
);
}
Problems will occur when you haven't selected anything yet or if there is a game that doesn't have a clip. So you shouldn't render the Video component if this value is not properly set.

React Native: Text strings must be rendered within a <Text> component

I am trying to create a Profile page where the user can upload an image as the react-native-elements Avatar and update his profile information on a native-base form element.
I am also using the React Native default ImageEditor for image cropping and ImagePicker from Expo to select images.
But when I open the app on Expo, i get this error
Invariant Violation: Invariant Violation: Text strings must be rendered within a component
Below is the code that I am using.
Please help.
import React from "react";
import {
View,
Text,
FlatList,
ActivityIndicator,
TouchableOpacity,
StyleSheet,
ImageEditor
} from "react-native";
import { Avatar } from "react-native-elements";
import { Container, Content, Form, Input, Label, Item } from 'native-base';
import * as Expo from 'expo';
export default class ProfileScreen extends React.Component {
static navigationOptions = {
}
constructor(props) {
super(props);
this.state = {
loading: false,
image: null,
error: null,
refreshing: false
};
}
async _pickImage() {
let result = await Expo.ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (result.cancelled) {
console.log('got here');
return;
}
let resizedUri = await new Promise((resolve, reject) => {
ImageEditor.cropImage(result.uri,
{
offset: { x: 0, y: 0 },
size: { width: result.width, height: result.height },
displaySize: { width: 100, height: 100 },
resizeMode: 'contain',
},
(uri) => resolve(uri),
() => reject(),
);
});
// this gives you a rct-image-store URI or a base64 image tag that
// you can use from ImageStore
this.setState({ image: resizedUri });
}
render () {
let { image } = this.state;
return (
<Container>
<Content>
<View style={{flex:1, flexDirection: 'column', alignContent: 'flex-start', marginLeft: 20}}>
<View style={{flex:1, flexDirection: 'row', alignContent: 'flex-end'}}>
<TouchableOpacity onPress={() => alert('Save')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Save</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('Cancel')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Cancel</Text>
</TouchableOpacity>
</View>
<View style={{height: 30}}></View> //Empty view
<View style={{alignContent: 'center'}}>
<Avatar rounded size="xlarge" title="Profile Photo" source={{ uri: this.state.image }} onPress={this._pickImage}/>
</View>
<View style={{height: 30}}></View> //Empty view
<Form>
<Item floatingLabel>
<Label style={styles.labelText}>First Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Last Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Email</Label>
<Input/>
</Item>
</Form>
</View>
</Content>
</Container>
)
}
}
const styles = StyleSheet.create({
labelText: {
fontSize: 12,
color: '#1f618d',
fontWeight: '100'
}
});
the problem is the way that use comment in render //Empty View use something like that {/* Empty view */}
Comments inside JSX must have the following syntax.
{/* Empty view */}
Remove comment using like //Empty view
if you wish to add comment in render return method you have to use {/*Empty View*/} something like this.
Instead of
<View style={{height: 30}}></View> //Empty view
write
<View style={{height: 30}}>{/*Empty View*/}</View>
you can not add comment directly like //comments in return function, only allow to in render or business logic parts.
Thanks
remove the // comment
make use of jsx commenting style
{/* comment */}
This can happen if you pass and empty string into a component, which is then "rendered" within a <Text> element.