How can i get back my data list after searching by words? - javascript

i use Flatlist and search by words on renderHeader() function. I can filter but when i delete letters, i couldn't get main list again. I think there is a logic problem but i couln't find after trying something...
i've got a new one when i fixed problem. I tried to fix but i couldn't do that, i should put the problem in front of experts :)
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data);
//search state
const [search, setSearch] = useState('');
//search filter
searchFilter = text => {
// onChangeText
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
//search function
renderHeader = () =>{
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
//setStates
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
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}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
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,
},
})
Thanks for your help

Filter Data
onSearchText = (value) => {
this.setState({searchText: value})
if(value.trim() == "" || value == null){
this.setState({list: this.state.list}
} else {
let filter = this.state.list.fillter(data => {
// data fillter logic //
return data;
})
this.setState({filterData: filter})
}
Render FlatList
<FlatList
extradata={this.state}
data={searchText ? filterData : list}
/>

I fixed...
How?
My main data state is constant, i'm filtering on data list with filter state. So my data list doesn't change anytime.
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
const Flatlistexample = () => {
//main list state
let [list, setList] = useState(data)
//search state
const [search, setSearch] = useState('')
//filter state
const [updated, setUpdated] = useState(data)
//search filter
searchFilter = text => {
// onChangeText
if (text) {
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1
})
setUpdated(newData)
}
//search function
renderHeader = () => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
searchFilter(text)
setSearch(text)
}}></TextInput>
<Text
style={{
alignItems: 'flex-start',
color: 'black',
fontSize: 22,
}}>
{search}
</Text>
</View>
)
}
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//i'm showing filter state
data={updated}
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}
//called search function
ListHeaderComponent={renderHeader()}
/>
</SafeAreaView>
)
}
export default Flatlistexample
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,
},
})
/*
else if(text.length > uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}else if(text.length<uzunluk){
setList(data)
const newData = list.filter(item => {
const listItem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return listItem.indexOf(text.toLowerCase()) > -1;
})
setList(newData)
}
*/

Related

Displaying a Image from the Camera

I am relatively new to React-Native and mobile app development. I am trying to create a clone of Instagram. And in the post screen what I do is I have a button Camera and once I click on it, that should take me to CameraView screen. And in the CameraView screen I will take a picture using expo-camera and save the picture in a variable. So here, I want to export the picture and then import it in my Post screen, so that the user can have a preview of what the picture looks like before uploading. And another thing to note is that, the Post screen will by default have a Placeholder image and once the image is taken the placeholder image has to be replaced with the image.
I tried this code but it didnt work.
My Post screen :-
import { View, Text, Image, TextInput } from 'react-native';
import React, { useState, useEffect } from 'react'
import * as Yup from 'yup';
import { Formik } from 'formik'
import { Button, Divider } from 'react-native-elements';
import { useNavigation } from '#react-navigation/native';
import CameraView, { takePicture } from '../../screens/CameraView';
const PLACEHOLDER_IMG = require('../../assets/defImg.png')
const uploadPostSchema = Yup.object().shape({
caption: Yup.string().max(2200, 'Caption cannot exceed character limit.')
})
const FormikPostUploader = ({route}) => {
const [thumbnailUrl, setThumbnailUrl] = useState(PLACEHOLDER_IMG)
const navigation = useNavigation()
const handleCameraPress = () => {
UserImage = takePicture()
setThumbnailUrl(UserImage)
navigation.navigate('CameraView')
}
return (
<Formik
initialValues={{ imageUrl: '', caption:'' }}
onSubmit={(values) => console.log(values)}
validationSchema={uploadPostSchema}
validateOnMount={true}>
{({
handleBlur,
handleChange,
handleSubmit,
values,
errors,
isvalid
}) => (
<>
<View style={{ margin: 20, justifyContent: 'space-between', flexDirection: 'row' }}>
<Image source={thumbnailUrl} />
<View style={{ flex: 1, margin: 15 }}>
<TextInput
placeholder='Write a caption...'
placeholderTextColor='gray'
multiline={true}
style={{ color: 'white', fontSize: 17 }}
onChangeText={handleChange('caption')}
onBlur={handleBlur('caption')}
value={values.caption}
/>
</View>
</View>
<Divider width={0.5} orientation='vertical'/>
<View style={{ alignItems: 'center', marginTop: 15 }}>
<Text style={{ fontSize: 18, fontWeight: 'bold', color: 'white' }}>Choose Image</Text>
</View>
<View style={{ justifyContent: 'space-between', flexDirection: 'column', margin: 20 }}>
<View style={{ justifyContent: 'space-between', flexDirection: 'row', margin: 30 }}>
<Button title='Camera' onPress={handleCameraPress}/>
<Button title='Gallery' onPress={() => navigation.navigate('GalleryView')} />
</View>
<Button onPress={handleSubmit} title='Post' disabled={isvalid} />
</View>
</>
)}
</Formik>
)
}
export default FormikPostUploader
And my CameraView screen :-
import { View, Text, Image, StyleSheet, Button } from 'react-native'
import React, {useState, useEffect} from 'react'
import { Camera } from 'expo-camera'
import { TouchableOpacity } from 'react-native'
import { useNavigation } from '#react-navigation/native'
import { PLACEHOLDER_IMG } from '../components/newPost/FormikPostUploader'
export const takePicture = async(camera) => {
const data = await camera.takePictureAsync(null)
return data.uri
}
const Header = () =>{
const navigation = useNavigation()
return (
<View style = {styles.headerContainer}>
<TouchableOpacity style = {{marginBottom:15}} onPress={() => navigation.goBack()}>
<Image source = {require('../assets/back.png')} style = {{width:35, height:35, margin:20}}/>
</TouchableOpacity>
<Text style={{color:'white', fontWeight: '700', fontSize:20, marginRight: 25, marginTop:35, marginBottom:15}}>New Post</Text>
<Text> </Text>
</View>
)
}
const CameraView = () => {
const UserImage = takePicture()
const navigation = useNavigation()
const [hasCameraPermission, setHasCameraPermission] = useState(null)
const [thumbnailUrl, setThumbnailUrl] = useState(PLACEHOLDER_IMG)
const [camera, setCamera] = useState(null)
const [type, setType] = useState(Camera.Constants.Type.back)
const captureImage = async () => {
if (camera) {
const UserImage = await takePicture(camera)
setThumbnailUrl(UserImage)
}
}
useEffect(() => {
(async() => {
const cameraStatus = await Camera.requestCameraPermissionsAsync()
setHasCameraPermission(cameraStatus.status === 'granted')})()},
[])
if (hasCameraPermission === null) {
return <View/>
}
if (hasCameraPermission === false){
return <Text>Enable access for Camera to proceed</Text>
}
return (
<View style={{ flex: 1, backgroundColor: 'black'}}>
<Header/>
<Camera
ref = {ref => setCamera(ref)}
style={styles.fixedRatio}
type={type}
ratio={'1:1'}/>
<View style = {styles.cameraContainer}>
<TouchableOpacity onPress={() => {setType(type === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back)}}>
<Image source={require('../assets/turn-camera.png')} style = {{width:70, height:70, margin: 15}}/>
</TouchableOpacity>
<TouchableOpacity onPress={() => {captureImage(), navigation.goBack(), console.log(UserImage)}}>
<Image source={require('../assets/camera-shutter.png')} style = {{width:70, height:70, marginRight:60}}/>
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
cameraContainer: {
flex:0.15,
backgroundColor: 'black',
flexDirection:'row',
justifyContent: 'space-between',
alignItems: 'center',
},
fixedRatio: {
flex:0.99,
aspectRatio:0.9
},
headerContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor:'black'
},
icon: {
width:25,
height: 25,
marginHorizontal:15,
marginTop:30,
},
iconContainer: {
flexDirection:'row',
justifyContent: 'space-between',
height:50,
},
}
)
export default CameraView
Am I doing anything wrong. Can you help me fix this. Thanks in advance!

Resulting in a blank screen when listing data with Firebase(Firestore) in React Native

Data listing process with Firebase(Firestore) in React Native.
In the video I watched, he wrote and ran the code that lists the coins belonging to the user using firestore. It did not work even though I wrote the same codes. What is the reason? the code does not give an error, the screen appears, but it does not list.
The problem is that when I did the listing in console it worked. However, when I try to list with FlatList, the screen appears blank.
import { View, Text, SafeAreaView, TouchableOpacity, FlatList } from 'react-native'
import React, { useContext, useState, useEffect } from 'react'
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
import IconFA from 'react-native-vector-icons/FontAwesome'
import { deviceWidth, deviceHeight } from '../../utils/dimensions'
import { AuthContext } from '../../navigation/AuthProvider'
import { Formik, validateYupSchema } from 'formik'
import * as yup from 'yup'
import { firebase } from '#react-native-firebase/auth'
import auth from '#react-native-firebase/auth'
import firestore from '#react-native-firebase/firestore'
const color = '#aaa';
const HomeScreen = ({ navigation }) => {
const renderItem = (item) => {
<TouchableOpacity
key={item.id}
style={{
flexDirection: 'row',
width: '95%',
height: 60,
borderWidth: 1,
margin: 10,
borderRadius: 20,
padding: 10,
justifyContent: 'space-between',
alignItems: 'center'
}}>
<View style={{ flex: 1 }}>
<Text style={{
textAlign: 'left',
fontSize: 18
}}>{item.coinID}</Text>
</View>
<View style={{ flex: 1 }}>
<Text style={{
textAlign: 'right',
fontSize: 18
}}>{item.value}</Text>
</View>
</TouchableOpacity>
}
const { signOut, user } = useContext(AuthContext);
const [currentUser, setCurrentUser] = useState({});
const [userCoinList, setUserCoinList] = useState([]);
const usersColl = firestore().collection('users');
const coinsColl = firestore().collection('coins');
const userCoinsColl = firestore().collection('userCoins');
useEffect(() => {
return usersColl
.doc(user.uid)
.get()
.then(result => {
setCurrentUser(result.data());
userCoinsColl.onSnapshot((querySnapshot) => {
let list = [];
querySnapshot.forEach(doc => {
const { userID, coinID, value } = doc.data();
if (userID == user.uid) {
list.push({
id: doc.id,
userID,
coinID,
value
});
setUserCoinList(list);
}
});
});
});
}, []);
return (
<SafeAreaView style={{ width: '100%', height: '100%' }}>
<View style={{
width: '100%',
height: '90%',
padding: 5,
flex: 1,
alignItems: 'center'
}}>
<View>
<FlatList
style={{ flex: 3, backgroundColor: '#f00' }}
data={userCoinList}
keyExtractor={item => item.id}
renderItem={renderItem}
/>
{console.log(userCoinList)}
</View>
</View>
</SafeAreaView>
)
}
export default HomeScreen
Your renderItem function does not return anything.
Here is a fix.
const renderItem = (item) => {
return <TouchableOpacity
key={item.id}
style={{
flexDirection: 'row',
width: '95%',
height: 60,
borderWidth: 1,
margin: 10,
borderRadius: 20,
padding: 10,
justifyContent: 'space-between',
alignItems: 'center'
}}>
<View style={{ flex: 1 }}>
<Text style={{
textAlign: 'left',
fontSize: 18
}}>{item.coinID}</Text>
</View>
<View style={{ flex: 1 }}>
<Text style={{
textAlign: 'right',
fontSize: 18
}}>{item.value}</Text>
</View>
</TouchableOpacity>
}

data size bigger than 1 has rendering issue

data that worked looks like this
(I used JSON.stringify function to see how the data looks like)
[{"_id":"612e60c4ce136a1f4454c938", "individualPurchasePrice":9800,"teamPurchasePrice":640, "eventDealCategory":"DysonHairDryer"}]
below is the data that didn't work
[{"_id":"612e60c4ce136a1f4454c938", "individualPurchasePrice":9800,"teamPurchasePrice":640, "eventDealCategory":"JMWHairDryer"}, {"_id":"612e60c4ce136a1f4454c938", "individualPurchasePrice":9800,"teamPurchasePrice":640, "eventDealCategory":"JMWHairDryer"},]
this is the error message
Element type is invalid:expected a string (for built-in components) or a class/function (for composite components) but got: object.
import React from 'react'
import { SafeAreaView, View, Dimensions, Text, ScrollView } from 'react-native'
import ItemStore from '../stores/ItemStore'
import ImageManager from '../images/ImageManager'
import ItemListWithoutCategory from '../components/item/ItemListWithoutCategory'
import TimeDealItemComponent from '../components/item/TimeDealItemComponent'
const dims = Dimensions.get('window')
const TimeDealItemScreen = ({ route, navigation }) => {
const { eventDealCategoryName } = route.params
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView style={{ height: 40, backgroundColor: 'red' }}>
<ImageManager
source='TimeDealGradientImage'
style={{
position: 'absolute',
width: '100%',
height: '100%',
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
/>
<ItemListWithoutCategory
isFrom='TimeDealItemScreen'
ItemSeparatorComponent={<View style={{ height: 16 }} />}
ListFooterComponent={
<>
<View style={{ height: 16, backgroundColor: 'transparent' }} />
</>
}
data={ItemStore?.eventDealItems?.filter(
(item) => item.eventDealCategory === eventDealCategory,
)}
renderItem={({ item, index }) => (
<View style={{ paddingHorizontal: 8 }}>
<TimeDealItemComponent item={item} index={index} />
</View>
)}
ListFooterComponent={
<>
<View style={{ height: 16, backgroundColor: 'transparent' }} />
</>
}
/>
</ScrollView>
</SafeAreaView>
)
}
export default TimeDealItemScreen
import React, { useState, useRef, useEffect, useCallback } from 'react'
import { FlatList } from 'react-native'
import ItemStore from '../../stores/ItemStore'
import { observer } from 'mobx-react-lite'
import UserStore from '../../stores/UserStore'
import { useNavigation } from '#react-navigation/native'
import viewabilityConfig from '../config/viewabilityConfig'
const ItemListWithoutCategory = observer(
({
ListEmptyComponent,
ListFooterComponent,
ItemSeparatorComponent,
data,
renderItem,
ListHeaderComponent,
isFrom,
ref,
onEndReached,
numColumns,
}) => {
const navigation = useNavigation()
const onViewableItemsChanged = useCallback(
({ viewableItems, changed }) => {
changed.forEach((item) => {
if (item.isViewable) {
const addedImpressionItems = {
itemId: item.item?._id,
itemTitle: item.item?.itemTitle,
loggedAt: new Date(),
isFrom,
}
ItemStore.addImpressionItems(addedImpressionItems)
}
})
},
[ItemStore.screenOnFocusMyOrder],
)
const viewabilityConfigCallbackPairs = useRef([
{ viewabilityConfig, onViewableItemsChanged },
])
return (
<FlatList
ref={ref}
viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs.current}
data={data}
ListHeaderComponent={ListHeaderComponent}
renderItem={renderItem}
keyExtractor={(item, index) => item?._id + index.toString()}
ListEmptyComponent={ListEmptyComponent}
ListFooterComponent={ListFooterComponent}
ItemSeparatorComponent={ItemSeparatorComponent}
onEndReached={onEndReached}
numColumns={numColumns}
/>
)
},
)
export default ItemListWithoutCategory
import React, { useState, useEffect } from 'react'
import { View, TouchableOpacity, Dimensions } from 'react-native'
import BlackText from '../texts/BlackText'
import GrayText from '../texts/GrayText'
import BasicButton from '../buttons/BasicButton'
import { observer } from 'mobx-react-lite'
import UserStore from '../../stores/UserStore'
import OrderStore from '../../stores/OrderStore'
import ImageManager from '../../images/ImageManager'
import backendApis from '../../utils/backendApis'
import { useNavigation } from '#react-navigation/native'
import ItemStore from '../../stores/ItemStore'
import RedText from '../texts/RedText'
import FastImage from 'react-native-fast-image'
import ImageTextTimer from '../texts/ImageTextTimer'
import commaNumber from 'comma-number'
const dims = Dimensions.get('window')
const TimeDealItemComponent = observer(({ item, index }) => {
const FULL_GAGE_WIDTH = 70
const CURRENT_GAGE_WIDTH = item.stockSoldPercentage
const GAGE_HEIGHT = 16
const navigation = useNavigation()
const TRANSPARENT_GRAY_CIRCLE_SIZE = 80
const [eventDealStatusHere, setEventDealStatusHere] = useState(0)
const [orderRecord, setOrderRecord] = useState('unpurchased')
useEffect(() => {
const eventStartedDate = new Date(item.eventDealStartedAt) // x
const now = new Date().getTime() // y
const oneDayTerm = 1000 * 60 * 60 * 24 * 1 // 7일
const stockleft = item.eventDealStock - item.totalOrderQuantity
if (eventStartedDate > new Date(now)) {
setEventDealStatusHere('preOpened')
} else if (
eventStartedDate < new Date(now) &&
eventStartedDate > new Date(now - oneDayTerm) &&
stockleft > 0
) {
setEventDealStatusHere('opened')
} else if (
eventStartedDate < new Date(now) &&
eventStartedDate > new Date(now - oneDayTerm) &&
stockleft <= 0
) {
setEventDealStatusHere('temporarilyClosed')
} else setEventDealStatusHere('closed')
}, [])
useEffect(() => {
if (
OrderStore.loadedUserOrdersList.find(
(order) =>
[
'pre-shipping',
'shipping',
'exchanging',
'arrived',
'reviewed',
].includes(order.status) && item._id === order.itemInfo.itemId,
)
) {
setOrderRecord('purchased')
} else {
setOrderRecord('unpurchased')
}
}, [OrderStore.loadedUserOrdersList])
const StockInfoTextComponent = ({ text }) => {
return (
<View
style={{
flexDirection: 'row',
alignContent: 'center',
// backgroundColor: 'grey',
}}
>
<GrayText text={text} fontSize={14} dark numberOfLines={1} />
</View>
)
}
const StockInfoText = () => {
if (eventDealStatusHere === 'preOpened') {
return (
<StockInfoTextComponent
text={`${commaNumber(item.eventDealStock)}개 입고 예정`}
/>
)
}
if (eventDealStatusHere === 'temporarilyClosed') {
return <StockInfoTextComponent text='일시적 물량 소진' />
}
if (eventDealStatusHere === 'closed') {
return <StockInfoTextComponent text='재고 전량 소진' />
}
return <></>
}
return (
<View style={{ width: '100%' }}>
<View
style={{
flex: 1,
width: '100%',
}}
>
<TouchableOpacity
style={{
backgroundColor: 'white',
marginTop: 12,
padding: 8,
borderRadius: 8,
}}
activeOpacity={1.0}
onPress={() => {
if (ItemStore.isLoadingItemScreen) {
return
}
ItemStore.setIsLoadingItemScreen(true)
navigation.push('MainStackDItemScreen', {
itemId: item._id,
itemInfo: item.itemInfo,
enteringComponent: 'TimeDealItemComponent',
})
setTimeout(() => {
ItemStore.setIsLoadingItemScreen(false)
}, 1000)
}}
>
<View
style={{
flexDirection: 'row',
marginTop: 4,
borderRadius: 4,
}}
>
<View
style={{
flex: 2,
flexDirection: 'column',
paddingHorizontal: 8,
}}
>
<View
style={{
paddingBottom: 8,
flexDirection: 'row',
paddingRight: 16,
}}
>
<BlackText
text={item.itemTitle}
fontSize={16}
numberOfLines={2}
/>
</View>
{/* 1.아이템타이틀 끝 */}
{/* 7. 게이지 시작 */}
<View
style={{
alignContent: 'center',
justifyContent: 'center',
}}
>
{eventDealStatusHere === 'opened' && (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}
>
<View
style={{
backgroundColor: '#E89FA1',
height: GAGE_HEIGHT,
width: FULL_GAGE_WIDTH,
borderRadius: 12,
}}
>
<View
style={{
backgroundColor: '#EC4F48',
height: GAGE_HEIGHT,
width: FULL_GAGE_WIDTH * CURRENT_GAGE_WIDTH,
borderRadius: 12,
}}
/>
</View>
{/* opened */}
{eventDealStatusHere === 'opened' && (
<View
style={{
flexDirection: 'row',
alignContent: 'center',
paddingLeft: 8,
// backgroundColor: 'grey',
}}
>
<GrayText
text={item.stockLeft}
fontSize={12}
numberOfLines={1}
/>
<GrayText
text='개 남음'
fontSize={12}
numberOfLines={1}
/>
</View>
)}
</View>
)}
</View>
{/* 7. 게이지 끝 */}
{orderRecord === 'purchased' && (
<View
style={{
borderRadius: 4,
paddingTop: 10,
}}
>
<>
<BasicButton
width={30}
text='이미 구매하신 아이템입니다.'
eventDealClosed
backgroundColor='#B3B4B7'
/>
</>
</View>
)}
</TouchableOpacity>
</View>
</View>
)
})
export default TimeDealItemComponent
below is the data that didn't work
[{"_id":"612e60c4ce136a1f4454c938", "eventDealCategory":"JMWHairDryer"}, {"_id":"612e60c4ce136a1f4454c938", "eventDealCategory":"JMWHairDryer"},]
It does not work in second example because instead of one object you have array of objects. To render them you need to map throught array.

How can I store the value of TextInput to local storage and get them when the app starts in react native?

I'm making a to-do list app. I need to store the input value locally or somewhere so that I can show them in the app even if the app is opened after closing once. Now when I'm closing the app and restarting all the previous values is being vanished. But I want to keep the previous data and If new data is given that will also be stored if I don't delete that manually. How can I solve this problem? I'm using expo.
Here is my code:
import React, { useState } from 'react';
import { View, Text, StyleSheet, Button, FlatList, TouchableOpacity, TextInput, ScrollView } from 'react-native';
import { MaterialIcons } from '#expo/vector-icons'
import Line from './Line';
function App() {
//storing data in array
const [initialElements, changeEl] = useState([
]);
const [value, setValue] = useState('')
const [idx, incr] = useState(1);
const [exampleState, setExampleState] = useState(initialElements);
//add button
const addElement = () => {
if (value != '') {
var newArray = [...initialElements, { id: idx, title: value }];
incr(idx + 1);
setExampleState(newArray);
changeEl(newArray);
}
}
//delete button
const delElement = (id) => {
let newArray = initialElements.filter(function (item) {
return item.id !== id
})
setExampleState(newArray);
changeEl(newArray);
}
//showing item
const Item = ({ title, id }) => (
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
<View style={{ borderWidth: 2, margin: 5, flex: 1, padding: 10, borderRadius: 10 }}>
<TouchableOpacity onPress={() => { alert(title) }}>
<Text >{title}</Text>
</TouchableOpacity>
</View>
<TouchableOpacity onPress={() => delElement(id)}>
<MaterialIcons name='delete' size={24} />
</TouchableOpacity>
</View>
);
//calling item for render
const renderItem = ({ item }) => {
<Item title={item.title} id={item.id} />
}
return (
<View style={styles.container}>
<View style={{ alignItems: 'center', marginBottom: 10 }}>
<Text style={{ fontSize: 20, fontWeight: '500' }}> To <Text style={{ color: 'skyblue', fontWeight: '900' }}>Do</Text> List</Text>
<Line />
</View>
<View>
<TextInput onChangeText={text => setValue(text)} placeholder="Enter to Todo" style={{ borderWidth: 2, borderRadius: 10, backgroundColor: 'skyblue', height: 40, paddingLeft: 10, borderColor: 'black' }}></TextInput>
</View>
<View style={{ alignItems: 'center' }}>
<TouchableOpacity onPress={() => addElement()} style={{ marginTop: 10 }}>
<View style={{ backgroundColor: 'black', width: 70, height: 40, justifyContent: 'center', borderRadius: 10 }}>
<Text style={{ color: 'white', textAlign: 'center' }}>Add</Text>
</View>
</TouchableOpacity>
</View>
<FlatList
style={{ borderWidth: 2, padding: 10, flex: 1, backgroundColor: '#EEDDD0', marginTop: 10 }}
data={exampleState}
renderItem={renderItem}
keyExtractor={item => item.id.toString()
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 20,
margin: 5,
}
})
export default App;
React Native provides a local storage option called AsyncStorage. You might use asyncstorage to save the data locally on the device and get that data inside useEffect() hook on startup.
You can find more about AsyncStorage here.
Although this is deprecated and now community package " #react-native-async-storage/async-storage " is used. The implementation remains the same.

View dont refresh when add a new json object in array. REACT NATIVE

the program compiles perfect, but when I scan a product, it doesn't refresh in the view.
I have mounted a mysql xampp with all the products. when querying a barcode. I get in response the detail of the product, and, add the json response with parse object in a array.
the view refresh when click TouchableOpacity, later of scan a product.
import React, {Component, useState, useEffect} from 'react';
import {Dimensions,Image, View, Text,AsyncStorage, TouchableOpacity, Grid, StyleSheet, ScrollView,ToastAndroid} from 'react-native';
import { SearchBar, Card, Icon } from 'react-native-elements';
import { BarCodeScanner } from 'expo-barcode-scanner';
//import { NumberList } from './NumberList';
const {width, height} = Dimensions.get('window');
const urlApi = "http://192.168.1.24/rst/api/getProduct.php";
const numbers = [1,2,3,4,5,6];
class SaleScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
scan: false,
result: null,
ScanResult: false,
hasPermission: true,
setHasPermission: true,
productos: [],
jwt: null,
};
//this.componentDidMount();
}
async componentDidMount(){
let _jwt = await AsyncStorage.getItem('userToken');
this.setState({
jwt: _jwt
});
}
_searchProduct = async (data) => {
try {
let response = await fetch(urlApi,{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer '+this.state.jwt
},
body: JSON.stringify({
CodiBarra: data
})
});
let responseJson = await response.json();
//console.log(responseJson);
if (responseJson.codibarra === null) {
//console.log("retorna falso");
return false;
}
else
{
if(this.state.productos != null)
{
this.state.productos.push(responseJson[0]);
//this.setState({productos: this.state.productos.push(responseJson[0])})
//console.log(this.state.productos);
}
else
{
this.state.productos.push(responseJson[0]);
}
}
} catch (error) {
console.error(error);
}
};
render(){
const { scan, ScanResult, result, hasPermission, setHasPermission, productos } = this.state;
const activeBarcode = ()=> {
this.setState({
scan: true
})
}
const handleBarCodeScanned = async ({ type, data }) => {
//console.log('scanned data' + data);
this.setState({result: data, scan: false, ScanResult: false});
this._searchProduct(data);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style= {{flex: 1}}>
{productos.length == 0 &&
<View style = {styles.button}>
<TouchableOpacity
onPress= {activeBarcode}
style={{
borderWidth:1,
borderColor:'rgba(0,0,0,0.2)',
alignItems:'center',
justifyContent:'center',
width:50,
height:50,
backgroundColor:'#fff',
borderRadius:50,
position: 'absolute',
marginTop: 10,
marginLeft: width - 100
}}
>
<Icon
type="font-awesome"
name="barcode"
/>
</TouchableOpacity>
</View>
}
{productos.length>0 &&
<View style={{flex:1}}>
<View style = {styles.button}>
<TouchableOpacity
onPress= {activeBarcode}
style={{
borderWidth:1,
borderColor:'rgba(0,0,0,0.2)',
alignItems:'center',
justifyContent:'center',
width:50,
height:50,
backgroundColor:'#fff',
borderRadius:50,
position: 'absolute',
marginTop: 10,
marginLeft: width - 100
}}
>
<Icon
type="font-awesome"
name="barcode"
/>
</TouchableOpacity>
</View>
<View style ={{flex:1,marginTop:20}}>
<ScrollView>
<NumberList products={this.state.productos} />
</ScrollView>
</View>
<View style ={{flex:1,marginTop:20}}>
<View style={{flexDirection:"row", height: 50, width: width, backgroundColor: "green", justifyContent: "center",}}>
<View style = {{ flexDirection:"column"}}>
<Text style = {{ fontSize: 40,color:"white"}}>{"TOTAL: "}</Text>
</View>
<View style={{justifyContent: "center", flexDirection:"row-reverse", paddingRight:20}}>
<Text style = {{ fontSize: 40,color:"white"}}>{result.precioventa}</Text>
</View>
</View>
</View>
</View>
}
{scan &&
<BarCodeScanner
onBarCodeScanned={handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
}
</View>
);
}
}
function NumberList(props) {
console.log("NUMBERLIST")
console.log(props);
const products = props.products;
const listItems = products.map((product) =>
// Correct! Key should be specified inside the array.
<ListItem key={product.key} value={product} />
);
return (
<View>
{listItems}
</View>
);
}
function ListItem(props) {
// Correct! There is no need to specify the key here:
const u = props.value;
return (
<View>
{u &&
<Card>
<View style={{flexDirection:"row"}}>
<Icon
name = "monetization-on"
size = {40}
/>
<View style={{flex:1, flexDirection: "column", paddingTop: 10}}><Text>{u.descripcion}</Text></View>
<View style = {{flexDirection:"row-reverse", paddingTop: 10}}><Text>{u.precioventa}</Text></View>
</View>
</Card>
}
</View>);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'black'
},
containerHome:{
backgroundColor: 'white',
height: height,
width: width,
flexDirection: 'column'
},
cardSales:{
backgroundColor: 'white',
flex: 1,
padding: 15,
borderWidth: 1,
borderRadius: 10,
borderColor: '#ddd',
borderBottomWidth: 7,
//shadowColor: '#000',
shadowColor: "#191919",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 20,
},
cardContent:{
flexDirection: 'row-reverse',
fontSize: 50
},
button:{
flexDirection: 'column',
marginTop: 20,
marginLeft: 20,
marginRight: 20,
},
contentActionFast:{
backgroundColor: 'white',
flexDirection: 'row',
alignItems:'center',
justifyContent: 'space-between',
flex:1
}
});
export default SaleScreen;
if anyone could help me I'd really appreciate it
Your component isn't re-rendering because in _searchProduct you're doing this.state.productos.push(responseJson[0]); to update the state object when you should be using setState(). Directly modifying the state, which you're doing now, won't trigger a re-render and could lead to other problems, which is why you should never do it and always use setState() (or a hook) to update state. This is mentioned in the docs here: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly.
Instead try:
this.setState((prevState) => ({
productos: [...prevState.productos, responseJson[0]]
});

Categories

Resources