im just a begineer with react native and i have this problem :
im working on a food app where you can check food items with checkbox , for each food checked it will be automatically stored in array like this :
const data = [
{
"Viande": Viande,
"Sauce": Sauce,
"Extra": Extra,
"Boisson": Boisson,
"Supplements": Supplements,
}
]
AsyncStorage.getItem("STORAGE_Data").then((datacart) => {
console.log("datacart = ", datacart)
if (datacart !== null) {
const cart = JSON.parse(datacart)
cart.push(datacart)
AsyncStorage.setItem("STORAGE_Data", JSON.stringify(cart))
console.log("cart 2:",JSON.stringify(cart))
}else{
AsyncStorage.setItem("STORAGE_Data", JSON.stringify(data))
console.log("else : " , data)
}
console.log("DATA:", JSON.stringify(data))
alert("done")
}).catch((error) => {
alert(error)
})
};
Everything works properly so far , im using asyncstorage to save all the data and get them in my Cart class where i have all the data , im using map() function to create a view for each time i add new food :
constructor(props) {
super(props);
this.state = {
dataCart: [],
};
}
componentDidMount()
{
try {
AsyncStorage.getItem('STORAGE_Data').then((cart) => {
if (cart !== null) {
const cartfood = JSON.parse(cart)
console.log(cart)
this.setState({ dataCart: cartfood })
console.log(JSON.stringify(this.state.dataCart))
}
})
}
catch (error) {
console.log(error)
}
}
and here is my map() function
{
this.state.dataCart.map((item , i) => {
return (
<View style={styles.rectangle}>
<Image style={{ width: normalize(200), height: normalize(64), alignSelf: 'center', marginLeft: normalize(-40) }} source={require("../assets/Tacos-M.png")}></Image>
<View>
<Text style={{ alignSelf: 'center', fontSize: normalize(17), marginTop: normalize(10) }} key={i}>{item.Viande}</Text>
<View style={{ flexDirection: 'row', alignSelf: 'center', marginTop: normalize(40) }}>
<TouchableOpacity onPress={() => alert('ok')}><Feather name="minus" color={'#D05A0B'} size={normalize(20)} style={styles.btnMoin} /></TouchableOpacity>
<Text style={{ fontSize: normalize(15), marginLeft: normalize(15) }}>2</Text>
<TouchableOpacity><Feather name="plus" color={'#D05A0B'} size={normalize(20)} style={styles.btnPlus} /></TouchableOpacity>
</View>
</View>
<View>
<TouchableOpacity><Feather name="x" color={'#D05A0B'} size={25} style={{ alignSelf: 'flex-start', marginTop: normalize(20), marginLeft: normalize(40), }} /></TouchableOpacity>
<Text style={{ fontSize: normalize(15), alignSelf: 'center', marginTop: normalize(27), marginLeft: normalize(35) }}>14 DT</Text>
</View>
</View>
)
})
}
So the problem is i can make a food list as a first order , but in the second order after i change the food choice my map() function doest not give food name like this :
it returns an empty text instead in the second order view
so tired console.log() to see if im getting real data or no and suddenly i figured out whenever i add another order the food list becomes like this :
the slash "/" symbol added for each order , i have no clue how but is there any solution to avoid these kind of symbols and get a clean and proper list for my data ?
If you look in your AsyncStorage.getItem callback, you'll see that you're doing:
cart.push(datacart)
meaning you're pushing your stringified cart onto your cart and then setting it back into AsyncStorage, when you probably want to be doing:
cart.push(data)
Edit:
Actually, you probably want to set data equal to the object rather than an array containing the object, and then change your code to either push the object to the cart array in the if statement or set the AsyncStorage with a new array containing the object like so:
const data = {
"Viande": Viande,
"Sauce": Sauce,
"Extra": Extra,
"Boisson": Boisson,
"Supplements": Supplements,
}
...
if (...) {
const cart = JSON.parse(datacart)
cart.push(datacart)
AsyncStorage.setItem("STORAGE_Data", JSON.stringify(cart))
} else {
AsyncStorage.setItem("STORAGE_Data", JSON.stringify([data]))
}
Related
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>
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
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 />}
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>
So I have a horizontal scrollview at the top of the view. The ScrollView contains nodes that have a specified width. I then have a border on the bottom of the ScrollView, like you can see in this screen cap: http://i.imgur.com/pOV1JFP.png
As you can see the child nodes of the ScrollView at the top don't reach the border. However, if I change the ScrollView to a View with flexDirection: 'row', then the child nodes fill the height fine. I've tried changing a few properties on the scrollview, such as:
Setting padding:0 on contentContainerStyle
automaticallyAdjustContentInsets={false}
Changing the values of contentInsets directly
None of those seem to fix the issue.
The scrollview code & style:
var styles = StyleSheet.create({
nav: {
padding: 0,
marginTop: 30,
flex: 1,
borderBottomWidth: 1,
borderColor: '#000000'
}
});
<ScrollView
style={[{width: screen.width}, styles.nav]}
horizontal={true}
showsHorizontalScrollIndicator={true}
automaticallyAdjustContentInsets={false}>
{dayNavItems}
</ScrollView>
The child components (makes up dayNavItems)
const styles = StyleSheet.create({
container: {
paddingLeft: 15,
paddingRight: 15,
width: 50,
justifyContent: 'center'
},
odd: {
backgroundColor: '#ccc'
},
selected: {
backgroundColor: '#39b54a'
},
text: {
fontFamily: 'Optima'
}
});
class DayNavItem extends React.Component {
static propTypes = {
day: React.PropTypes.object.isRequired,
odd: React.PropTypes.bool,
selectDay: React.PropTypes.func.isRequired,
selected: React.PropTypes.bool
};
render() {
const d = new Date(this.props.day.created_at);
const viewStyles = [styles.container];
if (this.props.selected) {
viewStyles.push(styles.selected);
} else if (this.props.odd) {
viewStyles.push(styles.odd);
}
return (
<TouchableOpacity style={viewStyles} onPress={() => this.props.selectDay(this.props.day.uuid)}>
<View>
<Text style={styles.text}>{getMonth(d)}</Text>
<Text style={styles.text}>{d.getDate()}</Text>
</View>
</TouchableOpacity>
);
}
}
Adding contentContainerStyle={{flexGrow: 1}} will do the trick.
<ScrollView contentContainerStyle={{flexGrow: 1}}>
</ScrollView>
There is a property called contentContainerStyle for ScrollView. I just solved a similar issue where I set flex: 1 to the ScrollView's styles, ScrollView's contentContainerStyle, and the child View component.
The other answers are correct, but just to provide a clarifying example:
<ScrollView contentContainerStyle={{ flex: 1 }}>
{children}
</ScrollView>
Setting flex: 1 for ScrollView's contentContainerStyle property did the trick for me.
I always end up creating this component in all my projects:
import * as React from 'react'
import { ScrollView, ScrollViewProps, StyleSheet } from 'react-native'
export function FullHeightScrollView(
props: {
children: React.ReactNode
} & Omit<ScrollViewProps, 'contentContainerStyle'>
) {
return (
<ScrollView contentContainerStyle={styles.grow} {...props}>
{props.children}
</ScrollView>
)
}
const styles = StyleSheet.create({
grow: { flexGrow: 1 },
})
Use it in place of React Native's ScrollView.
If ScrollView is wrapped inside of a SafeAreaView, put flex: 1 on SafeAreaView, this did the trick for me after hours of debugging...
Parent:
Child (styles ScrollView I implemented has nothing to do with the current issue you reported):
I have made a simple package for those who just want, like me, a working out of the box ScrollView, without having to apply all the time the styles to make it work properly.
https://github.com/SrBrahma/pagescrollview
Usage:
import { PageScrollView } from 'pagescrollview';
<PageScrollView>
{/** Your contents */}
</PageScrollView>