React-Native display image or video on mime/file type condition - node.js

i am making a gallery app using React-Native with node.js , I got a data from Node.js api, i want to display files either image or video depends on file type in a FlatList , I don't know how to write the condition for that,
{items.file_Name == 'mp4' ? Video : image }
I am trying to use the above code but i don't know how to get the file name. So please check my code
export default class HomeScreen extends React.Component {
constructor(Props) {
super(Props);
this.state = {
error: null,
Posts:[
{"id":166,"user_id":1,"description":"7th test","file_Name":[VID-WA0005.mp4"]},
{"id":10,"user_id":3,"description":" 6th test","file_Name":["10.jpg", "12.jpg"]},
{"id":9,"user_id":2,"description":" 5th test","file_Name":["9.jpg", "14.jpg"]} ],
}
}
render() {
const { Posts } = this.state
return (
<View style={styles.container}>
<View style={styles.tabContent}>
<FlatList style={styles.list}
data={this.state.Posts}
keyExtractor={(data_posts, index) => {
return data_posts.id.toString();
}}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
)
}}
renderItem={(post, id) => {
const items = post.item;
return (
<View style={styles.card}>
<View style={styles.cardHeader}>
<Text style={styles.title}>{items.description}</Text>
</View>
<View style={styles.cardContent}>
{items.file_Name.split('.').reverse()[0] == 'mp4' ?
<Video
source={{ uri: "http://192.168.1.2:3200/" + items.file_Name }}
style={{ width: '100%', height: 600 }}
resizeMode="cover"
paused={this.state.paused}
controls={true}
volume={this.state.volume}
muted={this.state.muted}
paused={this.state.paused}
onLoad={this.onLoad}
onBuffer={this.onBuffer}
onProgress={this.onProgress}
/>
:
<Image style={styles.cardImage} source={{ uri: "http://192.168.1.2:3200/" + item.file_Name }} />
}
</View>
</View>
)
}}
/>
{/* Flatlist Ends*/}
</View>
</View>
);
}
}
````
I tried with condition like
````{items.file_Name.split('.').reverse()[0] == 'mp4' ? <Video /> : <image />}````
But its not working because i am unable to get the file type.
If anyone know how to get the file name and how to display either video or image please tell me .

You can use endsWith() function is used to check whether the given string ends with the characters of the specified string or not
{items.file_Name.toString().endsWith("mp4") ? Video : image }

Try this
{items.file_Name.split('.').pop() == 'mp4'?<Video /> : <image />}

Related

in react native how i can change background color for every view element independent

for every view element independent when i press them without effect other views and save pressed state so next time i can find what ipressed still pressed and i can change color of other view when ipress them without lose stat of preview view
the problem is when i press one from two task the other task also change her background color
import React, { useState } from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
TouchableOpacity,
} from 'react-native';
function App() {
const [changBack,backgroundColor]=useState('green')
function changIt() {
backgroundColor('red');
}
const DATA1 = 'Task one';
const DATA2 = 'Task two';
return (
<View>
<TouchableOpacity
style={{
flex: 1,
backgroundColor:changBack,
padding: 20,
}}
onPress={changIt}>
<View>
<Text>{DATA1}</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
backgroundColor:changBack,
padding: 20,
}}
onPress={changIt}>
<View>
<Text>{DATA2}</Text>
</View>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection:'column',
textAlign:'right',
justifyContent:'space-evenly',
},
});
export default App;
Brother I notice you passed backgroundColor on Style for <TouchableOpacity> so definitely it won't work. backgroundColor is applicable for <View> only but not for TouchableOpcacity.
Do something like this ~
<View>
<View style={{backgroundColor:changBack}}>
<TouchableOpacity onPress={changeIt}>
<View>
<Text>Heyya</Text>
</View>
</ToucableOpacity>
</View>
</View>
or this,
<View>
<TouchableOpacity onPress={changeIt}>
<View style={{backgroundColor:changBack}}>
<Text>Heyya</Text>
</View>
</ToucableOpacity>
</View>

React Native no luck with fixing my FlatList - VirtualizedList: You have a large list that is slow to update

I have been trying to fix my virtualize list issue du to too many rendering apparently...
this is happening when I go back and forth, from one item here: restaurant (restaurant screen) to the flatList with the tab bar, I have also been trying to render less items, but even when the limit is down it doesn't seems to work...
What I use
I'm using a animated bottom sheet that display the flatList on top of the mapView
what I tried
I have been looking ,and tried that out
and also that
and those issues too
I have tried to use the Hook useMemo but apparently it does work for complex stuff such as arrays, or I my config of the dependency was wrong:
const renderMemo = useMemo(() => renderItem, []) //what should be in the array? data? !isLoading ? limit ? ( the limit is change when onEndReached)
(code below)
I have tried to make a pure component of my list (renderItem)
ISSUE
I still get :
VirtualizedList: You have a large list that is slow to update - make sure your renderItem function renders components that follow React performance best practices like PureComponent, shouldComponentUpdate, etc. Object {
"contentLength": 5148.66650390625,
"dt": 4164,
"prevDt": 2313,
}
and in this particular set up after not doing anything for a while I got that error:
_Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
at [native code]:null in dispatchAction
at containers/HomeScreen.js:87:16 in fetchData
at [native code]:null in flushedQueue
at [native code]:null in invokeCallbackAndReturnFlushedQueue_
I haven't tried shouldComponentUpdate as I don't really understand it... I mean I don't know where to locate it...
where should I head now ? memo maybe?
is there a way maybe to get less render from useEffect
CODE
repo native
HomeScreen:
const renderContent = () =>
!isLoading ? (
<View style={styles.firstParentViewRenderContent}>
....
<FlatListContents
data={data}
navigation={navigation}
setLimit={setLimit}
limit={limit}
skip={skip}
setSkip={setSkip}
handleColors={handleColors}
/>
</View>
flatListContents component:
const handleLoadMore = () => {
console.trace("handleMore");
// console.log(limit);
setIsLoadingMore(true);
// if (limit > 30) setIsLoadingMore(false);
if (!isLoading) {
setLimit(limit + 10);
setIsLoadingMore(false);
}
};
// const renderMemo = useMemo(() => renderItem, []);
const renderItem = ({ item }) => {
return (
<PureCompFlatlist
item={item}
handleColors={handleColors}
navigation={navigation}
/>
);
};
return (
<FlatList
data={data}
keyExtractor={(item) => String(item.placeId)}
renderItem={renderItem}
removeClippedSubviews={true}
maxToRenderPerBatch={20}
initialNumToRender={5}
windowSize={limit}
getItemLayout={(data, index) => {
return {
length: styles.flatList.height,
offset: 25 * styles.flatList.height,
index,
};
}}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.5}
// ListFooterComponent={renderFooter}
/>
PureCompFlat:
export class PureCompFlatlist extends PureComponent {
render() {
const { item, handleColors, navigation } = this.props;
return (
<TouchableOpacity
style={styles.flatList}
onPress={() =>
navigation.navigate("Restaurant", {
id: item.placeId,
name: item.name,
description: item.description,
rating: item.rating,
thumbnail: item.thumbnail,
color: handleColors(item.type),
})
}
>
<Image style={styles.flatListPic} source={{ uri: item.thumbnail }} />
<View style={styles.flatListContent}>
<View style={styles.flatListNameType}>
<Text style={styles.flatListText}>{item.name}</Text>
<Text style={styles.flatListText}>{item.type}</Text>
</View>
<Text style={styles.flatListText}>{item.rating}</Text>
<Text style={styles.flatListText} numberOfLines={2}>
{item.description}
</Text>
</View>
</TouchableOpacity>
);
}
}
thanks in advance

value for uri cannot be cast from double to string

I want to set a default image before i can upload any image from my gallery here is my code
state = {
user: {
avatar : require('../assets/user.png')
}
}
handlePickAvatar = async () => {
UserPermission.getCamerPermission()
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes : ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect:[4,3]
})
if (!result.cancelled) {
this.setState({ user: { ...this.state.user, avatar: result.uri } });
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.profile}>Profile</Text>
<View style={styles.avatarPlaceholder} >
<Image source={{ uri: this.state.user.avatar }} style={styles.avatar} />
</View>
<TouchableOpacity onPress={this.handlePickAvatar}>
<Text style={styles.text}>Load Image</Text>
</TouchableOpacity>
</View>
);
}
The results should be like this the user image must be defaulted but i get the error :value for uri cannot be cast from double to string
is there any solution for this ?
Thank you!
Updated!!
If it is a local image, specify the image url directly without uri as below:
<Image source={this.state.user.avatar}
uri should be specified only when the image is loaded from external source such as cloud/internet, as below. Let's assume cloudImage contain's the path to an image in the cloud.
<Image source={ cloudImage ? { uri: cloudImage } : this.state.user.avatar}
Check if user.avatar has the image then show the uploaded image. If it is not uploaded show the default image.
<View style={styles.container}>
<View style={styles.avatarPlaceholder}>
<Image
source={{ uri: this.state.user.avatar || 'default image path' }}
style={styles.avatar}
/>
</View>
<TouchableOpacity onPress={this.handlePickAvatar}>
<Text style={styles.text}>Load Image</Text>
</TouchableOpacity>
</View>
Use uri: this.state.user.avatar.toString() instead of uri: this.state.user.avatar and the error is gone.
Edit: your problem could've arised from the fact of loading in your store images with local paths via require('...'). In that scenario, the image is saved as a number.

React Native Flatlist inside Wrapper Component break the scolling

Hello i have a Problem with my wrapper component. If i put inside the Flatlist component the scrolling doesn't work anymore. I try to pur everywhere flex:1 (on flatlist, on the wrapper itself) but no changes still broken.
What is my mistake?
I expected the normal scroll behavior.
import React from 'react';
import { KeyboardAvoidingView, TouchableWithoutFeedback, Keyboard, Platform } from 'react-native';
const KeyboardAvoidingViewWrapper = ({ children, keyboardOffset }) => {
const additionalOffset = Platform.OS === 'ios' ? 0 : 17;
return (
<KeyboardAvoidingView
keyboardVerticalOffset={keyboardOffset ? keyboardOffset + additionalOffset : 65 + additionalOffset}
behavior={Platform.OS == "ios" ? "padding" : "height"}
style={{ flex: 1, }}
>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
{children}
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
)
}
export default KeyboardAvoidingViewWrapper;
In the Screen:
<KeyboardAvoidingViewWrapper>
<View style={{ flex: 1 }}>
<FlatList
data={data}
.....
/>
</View>
</KeyboardAvoidingViewWrapper>
Any help is more than appreciate. Thank you.
try giving 'position' to behavior property to your KeyboardAvoidingView.
<KeyboardAvoidingView behavior='position'>

Adding checkbox in between text description in react native

I have a view where I display a Heading and details which I get from server as below.
Now, in the question description there is a tag __CB__ which I need to replace with the checkbox, so, instead of that tag there will be a checkbox and rest of the text will continue as usual. I have separated the text based on tag and placed a checkbox in between but I haven't been able to align the view, either it gets arranged columnwise or if I try to arrange in row the text doesn't continue. Here is what I've tried.
Try 1:
<ScrollView
style={styles.scrollStyle}
scrollEnabled={scrollEnabled}
onContentSizeChange={this.onContentSizeChange}
>
<View style={styles.checkBoxTextContainer}>
<Text style={styles.questionText}>{questionText1}</Text>
<CheckBox
style={styles.checkboxStyle}
onClick={this.checkboxClick}
isChecked={this.state.isChecked}
checkedImage={<Image source={Images.checkBoxTick} />}
unCheckedImage={<Image source={Images.checkBoxEmpty} />}
// leftText={questionText1}
// rightText={questionText2}
/>
<Text style={styles.questionText}>{questionText2}</Text>
</View>
</ScrollView>
Styles
checkBoxTextContainer: {
flex: 1,
flexDirection: "row"
},
checkBoxStyle: {
width: 20,
height: 20
}
Result:
Try 2:
<ScrollView
style={styles.scrollStyle}
scrollEnabled={scrollEnabled}
onContentSizeChange={this.onContentSizeChange}
>
<Text style={styles.questionText}>{questionText1}</Text>
<CheckBox
style={styles.checkboxStyle}
onClick={this.checkboxClick}
isChecked={this.state.isChecked}
checkedImage={<Image source={Images.checkBoxTick} />}
unCheckedImage={<Image source={Images.checkBoxEmpty} />}
// leftText={questionText1}
// rightText={questionText2}
/>
<Text style={styles.questionText}>{questionText2}</Text>
</ScrollView>
Result:
I need the checkbox to continue in between text like the tag in my original image. Any help is appreciated.
Below is sample working code for your scenario.
import React, { Component } from 'react'
import { View, Text, StyleSheet } from 'react-native'
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
flexWrap: 'wrap'
},
cb: {
width: 10,
height: 10,
borderWidth: 2,
borderRadius: 2,
borderColor: 'red',
marginTop: 4,
marginHorizontal: 3,
}
})
const sampleData = [ 'Lorem', 'ipsum', 'dolor', 'sit', 'amet',
'CB',
'consectetur', 'adipiscing', 'elit.', 'Curabitur',
'CB',
' nunc', 'vel', 'scelerisque', 'tempus.', 'CB', 'Morbi', 'luc', 'abcd', 'xyzw'
]
const CheckBox = () => (
<View style={styles.cb} />
)
export default class CheckText extends Component {
renderData = (data) => {
const views = data.map((item) => {
if (item === 'CB') { return <CheckBox />}
return (<Text>{item}</Text>)
})
return views
}
render() {
return (
<View style={styles.container}>
{this.renderData(sampleData)}
</View>
)
}
}
And this is snapshot of output
Note:
I have parsed the text into array of strings. This is the key logic here. The way you decide to tokenize your input text will affect the rendering of your component. When I tried long strings as token, flexWrap: 'wrap' didn't work properly. See this issue for more details. Tokenizing into single words may do the job.
try to wrap the Text and Checkbox into <Text> tag.
Please try below solution. It may help you.
<ScrollView
style={styles.scrollStyle}
scrollEnabled={scrollEnabled}
onContentSizeChange={this.onContentSizeChange}
>
<View style={{
width:'100%',
flexDirection: "row"
}}>
// wrap into text tag
<Text>
// add space after first text
<Text style={styles.questionText}>{questionText1+" "}</Text>
<CheckBox
style={styles.checkboxStyle}
onClick={this.checkboxClick}
isChecked={this.state.isChecked}
checkedImage={<Image source={Images.checkBoxTick} />}
unCheckedImage={<Image source={Images.checkBoxEmpty} />}
/>
// add space before second text
<Text style={styles.questionText}>{" "+questionText2}</Text>
</Text>
</View>
</ScrollView>

Resources