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.
Related
I have created a React Context API, I have stored information such as first_name, hobbies, DOB etc in it. I have crated a state in the context file and a function that changes the state when called. I am using the context in SignUpForm1.js and SignUpForm2.js, I am trying to update the state of context variables when ever there is a change in the text field, but the data in the context is not updating.
UserData.js (Context)
import React from "react";
import { useState } from "react";
import {Text} from 'react-native';
import { createContext } from "react";
const SignUpContext = React.createContext({});
const UserData = (props)=>{
var state = {
pref_pronoun: "",
DOB: "",
course: "",
first_name: "",
hobby_1: "",
hobby_2: "",
hobby_3: "",
hobby_4: "",
hobby_5: "",
home_city: "",
last_name: "",
nationality: "",
student_email: "",
university: "",
}
const [userDetails , setDetails] = useState(state);
const updateFormData = (field, value) => {
setDetails({ [field]: value });
console.log(state);
};
return (
<SignUpContext.Provider value = {{state, updateFormData}}>
{props.children}
</SignUpContext.Provider>
)
}
export {SignUpContext, UserData} ;
SignUpForm1.js
import {
Image,
Text,
StyleSheet,
View,
StatusBar,
ScrollView,
RefreshControl,
} from "react-native";
import DropDown from "./DropDown";
import Input from "./Input";
import {
KeyboardAvoidingView,
TouchableWithoutFeedback,
Keyboard,
} from "react-native";
import { useCallback, useContext, useState } from "react";
import CustomButton from "./CustomButton";
import { useNavigation } from "#react-navigation/native";
import DateTimePickerModal from "react-native-modal-datetime-picker";
import { Button } from "react-native";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";
const HideKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
function SignUpForm1() {
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const s_context = useContext(SignUpContext);
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const navigation = useNavigation();
const NationalityData = ["Football", "Cricket", "Programmming", "Coding"];
const [refreshing, setRefreshing] = useState(false);
const onRefresh = useCallback(() => {
setRefreshing(true);
setTimeout(() => {
setRefreshing(false);
}, 2000);
}, []);
const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;
return (
<KeyboardAvoidingView behavior="padding">
<HideKeyboard>
<View
style={{
height: "100%",
width: "100%",
backgroundColor: "#f1be63",
}}
>
<View
style={{ backgroundColor: "#f1be63", height: statusBarHeight }}
>
<StatusBar barStyle="dark-content" />
</View>
<ScrollView
contentContainerStyle={styles.rootContainer}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={onRefresh}
/>
}
>
<Image
source={require("../assets/aeroplane.png")}
style={styles.image}
resizeMode="contain"
/>
<Text style={styles.header}>Let's get you set up</Text>
<Text style={styles.lowerHeader}>
(we promise that it won't take long)
</Text>
<View style={[styles.textFieldsContainer]}>
<View style={{ alignItems: "center" }}>
<Input
isLabel={true}
label="Preferred Pronoun"
placeholder="He/Him"
onChangeText={(text) => {
s_context.updateFormData("pref_pronoun", text);
}}
/>
<Input
isLabel={true}
label="First Name"
placeholder="Cameron"
onChangeText={(text) => {
s_context.updateFormData("first_name", text);
}}
/>
<Input
isLabel={true}
label="Last Name"
placeholder="Cox"
onChangeText={(text) => {
s_context.updateFormData("last_name", text);
}}
/>
<View
style={{
backgroundColor: "white",
width: "80%",
borderRadius: 5,
marginTop: 10,
}}
>
<Button
title="Date of Birth"
onPress={showDatePicker}
color="gray"
/>
</View>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
onConfirm={(date) => {
s_context.updateFormData('dob', date);
hideDatePicker();
}}
onCancel={hideDatePicker}
buttonTextColorIOS="white"
pickerContainerStyleIOS={{ backgroundColor: "#D89D35" }}
isDarkModeEnabled
/>
</View>
<View style={{ alignItems: "center" }}>
<DropDown
data={NationalityData}
placeholder="Nationality"
onSelect={(selectedItem, index) => {
s_context.updateFormData("nationality", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="University"
onSelect={(selectedItem, index) => {
s_context.updateFormData("university", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="Course"
onSelect={(selectedItem, index) => {
s_context.updateFormData("course", selectedItem);
}}
/>
<DropDown
data={NationalityData}
placeholder="HomeTown City"
onSelect={(selectedItem, index) => {
s_context.updateFormData("homeCity", selectedItem);
}}
/>
<CustomButton
isBorder={true}
title="Next"
onPress={() => {
navigation.navigate("SignUp2");
}}
/>
</View>
</View>
</ScrollView>
</View>
</HideKeyboard>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
rootContainer: {
height: "125%",
justifyContent: "flex-start",
alignItems: "center",
marginTop: 24,
},
textFieldsContainer: {
width: "100%",
flex: 1,
},
image: {
width: "25%",
height: "10%",
marginTop: 24,
},
header: {
color: "white",
fontSize: 26,
fontWeight: "bold",
marginVertical: 6,
},
lowerHeader: {
color: "white",
fontSize: 12,
marginBottom: 24,
},
});
export default SignUpForm1;
SignUpForm2.js
import {
View,
Text,
TouchableWithoutFeedback,
StyleSheet,
StatusBar,
ScrollView,
} from "react-native";
import { KeyboardAvoidingView } from "react-native";
import { Avatar } from "react-native-elements";
import Input from "./Input";
import DropDown from "./DropDown";
import { Keyboard } from "react-native";
import { Platform } from "react-native";
import { useNavigation } from "#react-navigation/native";
import CustomButton from "./CustomButton";
import { useState, useContext } from "react";
import { createNewUser } from "./util/auth";
import { SignUpContext, UserData } from "./GlobalUtil/UserData";
const HideKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
function SignUpForm2() {
const s_context = useContext(SignUpContext);
async function FinishBtnHandler()
{
console.log("Creating New User");
console.log("Email: " + emailText.trim());
console.log("Password: " + passwordText.trim());
await createNewUser(emailText.trim(), passwordText.trim());
}
const navigation = useNavigation();
const hobbiesData = ["Football", "Cricket", "Programmming", "Coding"];
const [emailText, setEmailText] = useState("");
function handleEmailText(newText) {
console.log("Email: " + newText);
setEmailText(newText);
}
const [passwordText, setPasswordText] = useState("");
function handlePasswordText(newText) {
console.log("Password: " + newText);
setPasswordText(newText);
}
function avatarPressHandler() {
console.log("Pressed!");
}
const statusBarHeight = Platform.OS === "ios" ? 50 : StatusBar.currentHeight;
return (
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }}>
<HideKeyboard>
<ScrollView>
<View
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
zIndex: 999,
}}
>
<View
style={{
backgroundColor: "#f1be63",
height: statusBarHeight,
}}
>
<StatusBar barStyle="dark-content" />
</View>
</View>
<View style={[styles.rootContainer, { paddingBottom: 48 }]}>
<View style={styles.lowerContainer}>
<Text style={styles.primaryText}>You're almost there!</Text>
<Avatar
rounded
size={170}
containerStyle={{ alignSelf: "center", marginTop: 24 }}
//icon={{ name: "user", type: "font-awesome" }}
overlayContainerStyle={{ backgroundColor: "#f1be63" }}
source={{
uri: "https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg",
}}
>
<Avatar.Accessory size={20} onPress={avatarPressHandler} />
</Avatar>
<Text
style={[
styles.secondaryText,
{ marginBottom: 8, marginTop: 16 },
]}
>
Express yourself & customize your avatar
</Text>
<Input
isLabel={true}
label="Student Email"
placeholder="cce22rnu#uea.ac.uk"
onChangeText={handleEmailText}
defaultValue={emailText}
/>
<Input
isLabel={true}
label="Create Password"
placeholder="iLoveyoushakila123"
onChangeText={handlePasswordText}
defaultValue={passwordText}
/>
<Input
isLabel={true}
label="Confirm Password"
placeholder="iLoveyoushakila123"
/>
<Text style={styles.secondaryText}>
Now the exciting part - select your top 5 hobbies
</Text>
<View style={{ alignItems: "center", marginTop: 16 }}>
<DropDown
data={hobbiesData}
onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_1", selectedItem);
}}
/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_2", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_3", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_4", selectedItem);
}}/>
<DropDown data={hobbiesData} onSelect={(selectedItem, index) => {
s_context.updateFormData("hobby_5", selectedItem);
}}/>
<CustomButton
isBorder={true}
title="Finish"
/*onPress={()=>{navigation.navigate("ConfirmId")}}*/ onPress={
FinishBtnHandler
}
/>
</View>
</View>
</View>
</ScrollView>
</HideKeyboard>
</KeyboardAvoidingView>
);
}
const styles = StyleSheet.create({
rootContainer: {
flex: 1,
justifyContent: "flex-start",
alignItems: "center",
backgroundColor: "#f1be63",
marginTop: 48,
backgroundColor: "#f1be63",
},
lowerContainer: {
flex: 1,
width: "100%",
alignItems: "center",
},
primaryText: {
color: "white",
fontSize: 24,
fontWeight: "bold",
},
secondaryText: {
marginTop: 8,
color: "white",
fontSize: 12,
fontWeight: "bold",
},
});
export default SignUpForm2;
You need to pass your userDetails state variable to the context, not the initial state value
<SignUpContext.Provider value={{ state: userDetails, updateFormData }}>
{props.children}
</SignUpContext.Provider>
Passing the initial state object will not see any updates you make.
Also, you should use the functional updates format to dynamically set properties in your state
setDetails((prev) => ({ ...prev, [field]: value }));
Finally, console logging state is a pointless exercise that often gives unexpected results. Just don't do it
The issue is that you are using state instead of userDetails in the updateFormData function. The state variable is never updated and remains the same initial value. To fix this, you should use setDetails instead of setState in the updateFormData function.
const updateFormData = (field, value) => {
setDetails({ ...userDetails, [field]: value });
console.log(userDetails);
};
Also, you are passing state in the SignUpContext.Provider value. You should pass userDetails instead of state.
return (
<SignUpContext.Provider value={{ userDetails, updateFormData }}>
{props.children}
</SignUpContext.Provider>
);
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!
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)
}
*/
Hello Everyone!
I want to display my notification data inside a Modal and using a FlatList, I am using react-native-modal for the Modal component, inside a Modal I have 3 main component like header, body, and footer.
header is just a title with the bottom line of it
body is a FlatList
and footer is a just Button for clear the notification
These 3 main components I wrap again with View component and I set the maxHeight for this (View) component
The body is the main issue here because the FlatList height is over the View height that I set the maxHeight, it's hard to explain and sorry, but you can see the picture at the bottom
And the important one is that I can't use flex:1 inside a Modal it's because a module that I use (react-native-modal) if I use flex: 1 it makes FlatList disappear
Picture
enter image description here
Code of ModalNotificationShowcase.jsx
import React, {
forwardRef,
memo,
useContext,
useEffect,
useImperativeHandle,
useState,
} from 'react';
import {View, Dimensions, Pressable, FlatList} from 'react-native';
import {Divider, Button, Icon, List} from '#ui-kitten/components';
import {IconHelper, Text, Modal} from '../Helper';
import {useRealmInstance, useRealmObjects} from '../../hooks';
import moment from 'moment';
import util from '../../utils';
import ThemeContext from '../../themes/ThemeContext';
const NotificationItem = memo(props => {
const {currentTheme} = props;
const [bgColor, setBgColor] = useState(
currentTheme === 'light' ? '#EDF1F7' : '#1A2138',
);
const notif = props.data;
const realm = props.realm;
return (
<Pressable
onPressIn={() =>
setBgColor(currentTheme === 'light' ? '#E4E9F2' : '#151A30')
}
style={{
padding: 12,
marginBottom: 12,
backgroundColor: bgColor,
borderRadius: 4,
}}
onPress={props.onPress}
onPressOut={() =>
setBgColor(currentTheme === 'light' ? '#EDF1F7' : '#1A2138')
}
>
<View style={{flexDirection: 'row'}}>
<IconHelper
color={notif.name === 'reminder' ? '#FF3D71' : '#0095FF'}
name={
notif.name === 'reminder'
? 'alert-triangle-outline'
: 'info-outline'
}
style={{marginRight: 8}}
onPress={() => console.log('Pressed')}
/>
<Text size={14} style={{flex: 1, marginBottom: 4}}>
{notif.message}
</Text>
</View>
<View style={{flexDirection: 'row', alignItems: 'center'}}>
<Text size={12} hint>
{moment(notif.createdAt).fromNow()}
</Text>
<View style={{flex: 1, alignItems: 'flex-end'}}>
<IconHelper
size={20}
color='#FF3D71'
name='trash-2-outline'
underlayColor='#E4E9F2'
onPress={() => {
realm.write(() => {
realm.delete(notif);
});
}}
/>
</View>
</View>
</Pressable>
);
});
const NotificationShowcase = props => {
const realm = useRealmInstance();
const notifications = useRealmObjects('notifications');
const {theme} = useContext(ThemeContext);
return (
<View
style={{
width: Dimensions.get('window').width - 48,
maxHeight: Dimensions.get('window').height - 48,
borderRadius: 4,
}}
>
// =====
// Header
// =====
<Text size={14} bold align='center' style={{padding: 12}}>
Notifikasi
</Text>
<Divider />
// =====
// Body
// =====
<View style={{padding: 12, flexGrow: 1, overflow: 'hidden'}}>
{notifications.isEmpty() ? (
<Text
size={14}
align='center'
hint
style={{
padding: 8,
marginBottom: 12,
backgroundColor: theme === 'light' ? '#EDF1F7' : '#1A2138',
borderRadius: 4,
}}
>
Belum ada notifikasi untuk saat ini
</Text>
) : (
// ======================
// The main issue is here
// ======================
<FlatList
data={notifications}
initialNumToRender={0}
maxToRenderPerBatch={1}
updateCellsBatchingPeriod={120}
numColumns={1}
keyExtractor={item => item._id.toString()}
renderItem={items => {
const notif = items.item;
return (
<NotificationItem
data={notif}
realm={realm}
currentTheme={theme}
/>
);
}}
/>
)}
// =====
// Footer
// =====
{!notifications.isEmpty() && (
<View
style={{
justifyContent: 'center',
alignItems: 'center',
}}
>
<Button
size='small'
appearance='outline'
accessoryLeft={props => (
<Icon {...props} name='trash-2-outline' />
)}
onPress={() => {
realm.write(() => {
realm.delete(notifications);
});
}}
>
Hapus semua
</Button>
</View>
)}
</View>
</View>
);
};
const ModalNotificationShowcase = forwardRef((props, ref) => {
let Modal_ref;
useImperativeHandle(ref, () => ({
show: () => Modal_ref.show(),
hide: () => Modal_ref.hide(),
}));
return (
<Modal
backdropStyle={{backgroundColor: 'rgba(9, 44, 76, .32)'}}
onBackdropPress={() => Modal_ref.hide()}
ref={refs => (Modal_ref = refs)}
>
<NotificationShowcase
navigate={props.navigate}
onPressNotifItem={() => Modal_ref.hide()}
/>
</Modal>
);
});
export default ModalNotificationShowcase;
Updated
const NotificationShowcase = props => {
return (
<View
style={{
flex: 1,
margin: 24,
borderRadius: 4,
}}
>
...
// =====
// Body
// =====
<View style={{flex: 1}}>
// ...
</View>
</View>
);
};
Here in my code I am trying to reload the page on Alert ok button . But its not working . How can I rerender the page on ok button , this is written on same page that I have to reload .
In my code I am sung form and inputfield compont for my login screen . All code is there below . I am tryning to is , when I am getting any respons like wrong username and password in alere then ok button I have to clear my form field . While here ists not happning . For this I am deleting my value mannully.
Please sugget .
import React from 'react';
import { Alert, Dimensions, ImageBackground, Text, View, TouchableOpacity, Platform , StatusBar} from 'react-native';
import Formbox from './ui/form';
import { RegularText, } from './ui/text';
import pkg from '../../package';
import _ from 'lodash';
import { LOGIN_BACKGROUND , LOGIN_BACKGROUND_DARK} from '../images'
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from 'react-native-responsive-screen';
import parentStyle from '../themes/parent.style'
import LottieView from 'lottie-react-native';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
const styles = {
imgBG: { width: '100%', height: '100%' },
mainContainer: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'flex-start',
height: deviceHeight,
paddingLeft: 20,
paddingRight: 20
},
logoContainer: { justifyContent: 'center', alignItems: 'center', background: 'red', marginTop: -50 },
logoView: {
borderWidth: 3,
borderColor: '#FFFFFF',
borderRadius: 4,
zIndex: -1,
...Platform.select({
ios: {
shadowOpacity: 0.45,
shadowRadius: 3,
shadowColor: '#090909',
shadowOffset: { height: 1, width: 0 }
},
android: {
elevation: 3
}
})
}
};
export default class Login extends React.Component {
constructor(props) {
super(props);
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.error) {
if (this.props.error.graphQLErrors[0] !== undefined) {
const errorDetails = _.map(_.split(this.props.error.graphQLErrors[0].message, '#'), _.trim)
const header = errorDetails[0];
const message = errorDetails[1];
Alert.alert(header, message, [{
text: 'OK',
onPress: () => this.props.navigation.push('Auth')
},]);
} else {
Alert.alert('Network Error', this.props.error.networkError.message, [{
text: 'OK',
onPress: () => this.props.navigation.navigate('Auth')
},]);
}
}
}
componentDidMount(){
StatusBar.setBarStyle('dark-content');
}
render() {
let loginForm = [
{ label: 'Username', icon: 'person', type: 'text' },
{ label: 'Password', icon: 'key', type: 'password' }
];
let submitBtn = { label: 'Login', OnSubmit: this.props.onLogin };
let appliedTheme = this.props.theme;
let appliedMode = this.props.mode;
return (
<ImageBackground source={appliedMode === 'light' ? LOGIN_BACKGROUND : LOGIN_BACKGROUND_DARK} style={styles.imgBG}>
<View style={styles.mainContainer}>
<View style={{ flexDirection: 'column', alignContent: 'center', justifyContent: 'center', flex: 1 }}>
<View style={{ flex: 0.75, justifyContent: 'center' }}>
<RegularText text={'Welcome,'} textColor='#57606F' style={{ fontSize: hp('5%') }} />
<RegularText text={'Sign in to continue'} textColor='#ABAFB7' style={{ fontSize: hp('3.5%') }} />
</View>
<View style={{ flex: 2 }}>
<View style={{ flex: 2 }}>
<Formbox
theme={parentStyle[appliedTheme] ? parentStyle[appliedTheme][appliedMode].primaryButtonColor : undefined}
mode={this.props.mode}
formFields={loginForm}
submit={submitBtn}
that={this}
mutation={this.props.token}
/>
<View style={{ height: hp(20), zIndex:10, top: -25}}>
{this.props.loading && (
<LottieView source={require('./animations/login_authentication.json')} autoPlay loop />
)}
</View>
<View style={{top:-70, zIndex:10}}>
{false && <View style={{ alignItems: 'center' }}>
<RegularText text={`v${pkg.version}`} textColor='#ABAFB7' style={{ fontSize: hp('2%') }} />
</View>}
<View style={{ alignItems: 'flex-end' }}>
<View style={{ flexDirection: 'row' }}>
<RegularText text={`New User?`} textColor='#4A494A' style={{ fontSize: hp('2%') }} />
<TouchableOpacity>
<RegularText text={` REGISTER`} textColor={parentStyle[appliedTheme] ? parentStyle[appliedTheme][appliedMode].primaryButtonColor : '#fff'} style={{ fontSize: hp('2%'), fontWeight: 'bold' }} />
</TouchableOpacity>
</View>
</View>
</View>
</View>
</View>
</View>
</View>
</ImageBackground>
);
}
}
////// Form ,js
import React, { Component } from 'react';
import { View, Platform, Dimensions } from 'react-native';
import { PrimaryBtn,PrimaryAbsoluteGradientBtn } from './buttons';
import { InputField, PasswordField } from './inputField';
import { Form } from 'native-base';
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from 'react-native-responsive-screen';
const deviceHeight = Dimensions.get('window').height;
const deviceWidth = Dimensions.get('window').width;
export default class Formbox extends Component {
constructor(props) {
super(props);
}
OnSubmit() {
let { formFields, that, submit, mutation } = this.props;
submit.OnSubmit.bind(that, formFields, mutation)();
}
OnChange(field, target) {
this.props.formFields.forEach(function (formField, indx) {
if (formField.label === field.label) {
formField.value = target;
}
});
}
renderFields(field, indx) {
let { label, icon, type } = field;
if (label && icon) {
if (type === 'password') {
return <PasswordField key={label + indx} type={type ? type : ''} label={label} icon={icon}
OnChange={this.OnChange} that={this} />;
}
return <InputField key={label + indx} type={type ? type : ''} label={label} icon={icon} OnChange={this.OnChange}
that={this} />;
}
}
render() {
let { formFields, submit, that , theme, mode} = this.props;
return (
<View style={{ width: '100%' }}>
<Form style={{ width: '95%' }}>
{formFields.map((field, indx) => this.renderFields(field, indx))}
<View style={{ marginTop: 60 }}>
<PrimaryAbsoluteGradientBtn label={submit.label} OnClick={this.OnSubmit} that={this} backgroundColor={theme}/></View>
</Form>
</View>
);
}
}
/// input fields js
import React, { Component } from 'react';
import { Icon, Input, Item, Label } from 'native-base';
import { View } from 'react-native';
import { DoNothing } from '../services/services';
class InputField extends Component {
constructor(props) {
super(props);
}
render() {
let { label, OnChange, icon, that,type, keyboardType } = this.props;
return (
<View>
<Item floatingLabel>
{icon && <Icon active name={icon}/>}
{label && <Label>{label}</Label>}
<Input
secureTextEntry={type === 'password'}
onChangeText={OnChange ? (e) => OnChange.bind(that, this.props, e)() : DoNothing.bind(this)}
keyboardType={keyboardType || 'default'}
autoCapitalize = 'none'
autoCorrect={false}
/>
</Item>
</View>
);
}
}
class PasswordField extends Component {
constructor(props) {
super(props);
this.state = {
isMasked: true
};
}
_toggleMask = () => {
this.setState({
isMasked: !this.state.isMasked
});
};
render() {
let { label, OnChange, icon, that, type } = this.props;
const { isMasked } = this.state;
return (
<View>
<Item floatingLabel>
{icon && <Icon active name={icon}/>}
<Label>{label}</Label>
<Input
autoCapitalize = 'none'
secureTextEntry={isMasked}
onChangeText={OnChange ? (e) => OnChange.bind(that, this.props, e)() : DoNothing.bind(this)}
/>
<Icon name={isMasked ? "md-eye-off" : "md-eye"} active type="Ionicons" onPress={() => this._toggleMask()}/>
</Item>
</View>
);
}
}
const styles = {
dark: {
color: "#000000"
},
light: {
color: "#EAEAEA"
}
}
export { InputField, PasswordField };
You can either do :
onPress: () => this.props.navigation.push('Auth')
or do something like :
onPress: () => this.setState({name:'random'})
These both will trigger re rendering, Hope it helps. feel free for doubts