I was trying to build a social media application. In the profile screen I have Flatlist that renders the information. It is alright when I'm in dubugging mode or in normal exporting mode (without different cpu architecures) but when I try to export and assemble the output apk with different architecture ap stops working when we are touching the profile bottom tap icon.
Do you have any idea what is happening when we are trying to export and assemble the release apk?
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable react-native/no-inline-styles */
import React, {useState, useEffect, useContext} from 'react';
import {
StyleSheet,
View,
TouchableOpacity,
KeyboardAvoidingView,
FlatList,
RefreshControl,
Text,
} from 'react-native';
import {Snackbar} from 'react-native-paper';
import jwtDecode from 'jwt-decode';
import Feather from 'react-native-vector-icons/dist/Feather';
import {AppScreen} from '../../Layouts';
import {
AppProfileHeader,
AppProfileBio,
AppProfileBioContent,
AppProfilePosts,
AppProfileTopNavHeader,
AppBioCallToActions,
AppProfileStepsSlider,
} from '../../Containers';
import {
AppInputContainer,
AppText,
ContactUserModal,
AppButton,
ProfileCommentsListModal,
AppUserPostComment,
AppCommentInput,
AppPostUploaderBox,
} from '../../Components';
import {Colors, Fonts, ScreenSize} from '../../Constants';
import {ScrollView} from 'react-native-gesture-handler';
import {AppContext, AuthStorage} from '../../Services';
import {ProfileApis, SettingsApis} from '../../Services/Apis';
export default function ProfileScreen({navigation}) {
const {
user,
setUser,
setUserPosts,
userPosts,
setUserProfileInfo,
userProfileInfo,
} = useContext(AppContext);
const restoreToken = async () => {
const token = await AuthStorage.getToken();
if (!token) {
return;
}
const decodedToken = jwtDecode(token);
setUser(decodedToken);
};
const [refreshing, setRefreshing] = useState(false);
const [userCategoryType, setUserCategoryType] = useState();
const [commentAccountText, setCommentAccountText] = useState('');
const [accountCommentList, setAccountCommentList] = useState('');
const [editUserConnectionInputs, setEditUserConnectionInputs] = useState(
false,
);
const [contactUserInfo, setContactUserInfo] = useState({});
const contactUserInfoTextChangeHandler = (key, text) => {
setContactUserInfo((prev) => {
return {
...prev,
[key]: text,
};
});
};
const [snackbarVisible, setSnackbarVisible] = useState(false);
const onDismissSnackBar = () => setSnackbarVisible(false);
const [contactModalVisible, setContactModalVisible] = useState(false);
const [profileCommentsVisible, setProfileCommentsVisible] = useState(false);
const modalVisibilityHandler = () => {
setContactModalVisible(!contactModalVisible);
};
const updateUserContactInfoHandler = async () => {
try {
const result = await SettingsApis.updateAccountDatum({
datum: {...contactUserInfo},
});
if (result.data.status) {
setEditUserConnectionInputs(false);
modalVisibilityHandler();
setSnackbarVisible(true);
}
} catch (error) {
console.log("can't update user contactInfo", error.message);
}
};
const profileCommentVisibilityHandler = () => {
setProfileCommentsVisible(!profileCommentsVisible);
};
const topHeaderNavigationHandler = (route, param) => {
navigation.navigate(route, param);
};
const imagePickerHandler = () => {
navigation.jumpTo('CreatePost');
};
const fetchProfileInfo = async () => {
if (await AuthStorage.getToken()) {
try {
const result = await ProfileApis.profileInfo({
account: user.xdefaultaccount,
});
if (result.data.status) {
setUserProfileInfo(result.data.datum);
setContactUserInfo(result.data.datum);
setRefreshing(false);
}
} catch (error) {
console.log(error.message);
}
}
};
const fetchPosts = async () => {
try {
const result = await ProfileApis.getPosts({
account: userProfileInfo.id,
});
if (result.data.status) {
setUserPosts(result.data.datum);
} else {
console.log('fetch error');
}
} catch (error) {}
};
const updateStar = async (score) => {
try {
const result = await ProfileApis.updateStar({
node: userProfileInfo.id,
vote: score,
});
if (result.status) {
fetchProfileInfo();
}
} catch (error) {
console.log(error.message);
}
};
const getAccountComments = async () => {
try {
const result = await ProfileApis.getAccountComments({
account: userProfileInfo.id,
});
if (result) {
setAccountCommentList(result.data.datum);
}
} catch (error) {
console.log(error.message);
}
};
const registerCommentAccount = async () => {
try {
const result = await ProfileApis.registerCommentAccount({
node: userProfileInfo.id,
content: commentAccountText,
});
if (result) {
getAccountComments();
setCommentAccountText('');
}
} catch (error) {
console.log(error.message);
}
};
const registerCommentLike = async (id) => {
try {
const result = await ProfileApis.registerCommentLike({
node: id,
});
if (result.data.status) {
getAccountComments();
}
} catch (error) {
console.log("can't register comment like", error.message);
}
};
const followUser = async () => {
try {
const result = await ProfileApis.follow({
node: userProfileInfo.id,
});
if (result) {
console.log(result);
}
} catch (error) {
console.log(error.message);
}
};
const updateStepHandler = async (step) => {
let fetchedSteps = userProfileInfo.step;
try {
if (fetchedSteps) {
fetchedSteps.splice(fetchedSteps.indexOf(step), 1);
}
const result = await SettingsApis.updateAccountStep({
step: fetchedSteps,
});
if (result.data.status) {
fetchProfileInfo();
}
} catch (error) {
console.log("can't update account step", error.message);
}
};
useEffect(() => {
restoreToken();
}, []);
useEffect(() => {
fetchProfileInfo();
}, [user]);
useEffect(() => {
fetchPosts();
getAccountComments();
setUserCategoryType(userProfileInfo.category);
}, [userProfileInfo]);
return (
<AppScreen style={styles.container}>
<AppProfilePosts
{...{
refreshControl: (
<RefreshControl refreshing={refreshing} onRefresh={restoreToken} />
),
posts: userPosts,
navigation,
ListEmptyComponent: () => {
return (
<>
<AppPostUploaderBox {...{imagePickerHandler}} />
</>
);
},
ListHeader: () => {
return (
<>
<AppProfileTopNavHeader
{...{
navigation,
topHeaderNavigationHandler,
username: userProfileInfo.account,
userProfileInfo,
user,
}}
/>
<AppProfileHeader
{...{fetchedProfileData: userProfileInfo, navigation}}
/>
<AppProfileBio
{...{
fetchedProfileData: userProfileInfo,
updateStar,
navigation,
}}>
<AppProfileBioContent
{...{fetchedProfileData: userProfileInfo}}
/>
<AppBioCallToActions
{...{
userProfileInfo,
user,
followUser,
modalVisibilityHandler,
profileCommentVisibilityHandler,
}}
/>
</AppProfileBio>
{userCategoryType === 'personal' ? (
<AppProfileStepsSlider
{...{
avatarUri: userProfileInfo.avatar,
steps: userProfileInfo.step,
updateStepHandler,
fetchProfileInfo,
}}
/>
) : null}
</>
);
},
}}
/>
<ContactUserModal
style={[styles.wrapperStyle]}
{...{
modalVisibilityHandler,
isVisible: contactModalVisible,
}}>
<ScrollView>
<View style={styles.contentWrapper}>
<TouchableOpacity
style={styles.closeButtonContainer}
onPress={modalVisibilityHandler}>
<Feather name="x" style={styles.closeIcon} />
</TouchableOpacity>
<View style={styles.titleContainer}>
<AppText
style={{
fontFamily: Fonts.iransansMedium,
fontSize: 16,
marginRight: 10,
textAlign: 'right',
}}>
{contactUserInfo.firstname} {contactUserInfo.lastname}
</AppText>
<AppText style={{padding: 8}}>
{contactUserInfo.biography}
</AppText>
</View>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('mobile', text)
}
editable={editUserConnectionInputs}
value={contactUserInfo.mobile}
placeholder="شماره موبایل"
inputStyle={{
textAlign: 'left',
fontSize: 16,
top: 2,
color: '#838383',
}}
IconComponent={
<AppText
style={{
fontFamily: Fonts.iransans,
fontSize: 16,
color: '#838383',
}}>
+98
</AppText>
}
/>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('phone', text)
}
placeholder="تلفن ثابت"
value={contactUserInfo.phone}
editable={editUserConnectionInputs}
inputStyle={{
textAlign: 'left',
fontSize: 16,
top: 2,
color: '#838383',
paddingLeft: 20,
}}
/>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('webpage', text)
}
value={contactUserInfo.webpage}
editable={editUserConnectionInputs}
placeholder="وبسایت"
inputStyle={{
textAlign: 'left',
paddingLeft: 15,
fontSize: 16,
top: 2,
color: '#838383',
}}
/>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('province', text)
}
placeholder="استان"
value={contactUserInfo.province}
editable={editUserConnectionInputs}
inputStyle={{
fontSize: 14,
top: 2,
color: '#838383',
}}
/>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('city', text)
}
placeholder="شهر"
value={contactUserInfo.city}
editable={editUserConnectionInputs}
inputStyle={{
fontSize: 14,
top: 2,
color: '#838383',
}}
/>
<AppInputContainer
onChangeText={(text) =>
contactUserInfoTextChangeHandler('address', text)
}
value={contactUserInfo.address}
editable={editUserConnectionInputs}
placeholder="آدرس"
inputStyle={{
fontSize: 14,
top: 2,
color: '#838383',
}}
/>
{user.xaccount === userProfileInfo.id && (
<View style={styles.buttonContainer}>
{editUserConnectionInputs ? (
<AppButton
onPress={updateUserContactInfoHandler}
activeOpacity={0.7}
fontSize={16}
fontFamily={Fonts.iransansMedium}
textColor={Colors.primary_component_bg}
style={[styles.ctaButton, {backgroundColor: 'green'}]}>
ذخیره
</AppButton>
) : (
<AppButton
onPress={() =>
setEditUserConnectionInputs(!editUserConnectionInputs)
}
activeOpacity={0.7}
fontSize={16}
fontFamily={Fonts.iransansMedium}
textColor={Colors.primary_component_bg}
style={styles.ctaButton}>
ویرایش
</AppButton>
)}
</View>
)}
</View>
</ScrollView>
</ContactUserModal>
<Snackbar
duration={1500}
style={{
backgroundColor: 'green',
padding: 0,
}}
visible={snackbarVisible}
onDismiss={onDismissSnackBar}>
<View
style={{
height: 20,
width: ScreenSize.width - 50,
}}>
<Text style={{color: 'white'}}>اطلاعات با موفقیت به ثبت رسید</Text>
</View>
</Snackbar>
<ProfileCommentsListModal
{...{modalVisibilityHandler: profileCommentVisibilityHandler}}
isVisible={profileCommentsVisible}>
<KeyboardAvoidingView>
<View style={[styles.contentWrapperProfileComments]}>
<View style={{paddingBottom: 58}}>
<FlatList
ListEmptyComponent={<Text> nothing here </Text>}
data={accountCommentList}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => {
return (
<AppUserPostComment {...{item, registerCommentLike}} />
);
}}
/>
</View>
<AppCommentInput
{...{
registerCommentAccount,
commentAccountText,
setCommentAccountText,
}}
/>
</View>
</KeyboardAvoidingView>
</ProfileCommentsListModal>
</AppScreen>
);
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
},
contentWrapper: {
height: ScreenSize.height,
width: '100%',
backgroundColor: 'white',
borderRadius: 10,
},
contentWrapperProfileComments: {
height: '100%',
width: '100%',
backgroundColor: 'white',
borderRadius: 10,
},
closeButtonContainer: {
height: 50,
width: '100%',
justifyContent: 'center',
},
closeIcon: {
fontSize: 30,
color: Colors.secondary_text,
marginLeft: 10,
},
titleContainer: {
padding: 5,
marginBottom: 20,
},
buttonContainer: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
width: '100%',
bottom: 20,
},
ctaButton: {
backgroundColor: Colors.primary_text,
width: '90%',
borderRadius: 4,
height: 45,
},
});
so can u add results from logcat? because self-closing apps because something wrong, like component cant rendering completely
Related
I am newer for using react-native, and wanna try to create a camera with filter. I'm blocked in step to recognize face. Have success to draw rectangle when face detected, but the problem is once it goes out of detection. The camera stop running as it fixes on the last real-time capture
Here is my code:
import { useState, useEffect, useRef } from 'react'
import { Camera } from 'expo-camera'
import * as MediaLibrary from 'expo-media-library'
import { Text, StyleSheet, View, TouchableOpacity } from 'react-native'
import Button from './Button'
import { Ionicons } from '#expo/vector-icons'
import * as FaceDetector from 'expo-face-detector'
export default function PCamera() {
const cameraRef = useRef(undefined)
const [faceDetected, setFaceDetected] = useState([])
const [lastImage, setImage] = useState(undefined)
const [hasUsePermssion, setUsePermission] = useState(false)
const [type, switchToType] = useState(Camera.Constants.Type.front)
const takePicture = async () => {
if (cameraRef) {
try {
const options = {
quality: 1,
base64: true,
exif: false,
}
const data = await cameraRef.current.takePictureAsync(options)
setImage(data.uri)
console.log(data)
} catch (err) {
console.error(err)
}
}
}
const swithMode = () => {
switchToType(
type === Camera.Constants.Type.front
? Camera.Constants.Type.back
: Camera.Constants.Type.front
)
}
const handleFacesDetected = ({ faces }) => {
setFaceDetected(faces)
}
useEffect(() => {
;(async () => {
const { status } = await Camera.requestCameraPermissionsAsync()
if (status === 'granted') {
setUsePermission(true)
}
})()
}, [])
if (hasUsePermssion === null) {
return <View />
}
if (hasUsePermssion === false) {
return <Text>No access to camera</Text>
}
return (
<View style={styles.cameraContainer}>
<View style={styles.overlay}>
<Camera
ref={cameraRef}
style={styles.camera}
type={type}
onFacesDetected={handleFacesDetected}
faceDetectorSettings={{
mode: FaceDetector.FaceDetectorMode.fast,
detectLandmarks: FaceDetector.FaceDetectorLandmarks.all,
runClassifications:
FaceDetector.FaceDetectorClassifications.none,
minDetectionInterval: 100,
tracking: true,
}}
>
{faceDetected.length > 0 &&
faceDetected.map((face) => (
<View
key={face.faceID}
style={{
position: 'absolute',
borderWidth: 2,
borderColor: 'red',
left: face.bounds.origin.x,
top: face.bounds.origin.y,
width: face.bounds.size.width,
height: face.bounds.size.height,
}}
/>
))}
</Camera>
</View>
<View style={styles.optionsContainer}>
<View>
<TouchableOpacity onPress={swithMode}>
<Text>
<Ionicons
name="camera-reverse-outline"
size={24}
color="black"
/>
</Text>
</TouchableOpacity>
</View>
<Button
icon="camera"
title="Take Photo"
onPress={takePicture}
style={styles.button}
/>
<View>
<Text>...</Text>
</View>
</View>
</View>
)}
const styles = StyleSheet.create({
cameraContainer: {flex: 1,
},
overlay: {
flex: 6,
borderBottomStartRadius: 75,
borderBottomEndRadius: 75,
overflow: 'hidden',
},
camera: {
flex: 1,
},
optionsContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
},
})
N.B: Don't take care of the Button, it's a custom component and works well
This is what I am trying. On focus of TextInput datepicker does get open but after selecting date it is not getting populated in TextInput field.
Where I am making mistake?
<TouchableOpacity>
<TextInput style={styles.textinputstyle} onFocus={()=>{setOpen(true)}} />
</TouchableOpacity>
<DatePicker modal mode="date" dateFormat="MM-DD-YYYY" open={open} date={date} onConfirm={date=> { setOpen(false) setDate(date) }} onCancel={() => { setOpen(false) }} />
set editable = false in TextInput
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
const [birthDate, setBirthDate] = useState('');
const showDatePicker = () => {
setDatePickerVisibility(true);
};
const hideDatePicker = () => {
setDatePickerVisibility(false);
};
const handleConfirm = date => {
setBirthDate(date);
hideDatePicker();
};
<TouchableOpacity onPress={showDatePicker}>
<TextInput
numberOfLines={1}
editable={false}
placeholder="Choose Your Date of Birth"
value={moment(birthDate).format('DD MMMM, YYYY')}
style={{
fontSize: 16,
paddingVertical: 10,
color: 'black',
}}
/>
<DateTimePickerModal
isVisible={isDatePickerVisible}
maximumDate={new Date(moment().add(-1, 'days'))}
mode="date"
onChange={date => setBirthDate(date)}
value={handleConfirm}
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
</TouchableOpacity>
import React, { useState,useEffect } from 'react';
import {
Text,
View,
StyleSheet,
TextInput,
SafeAreaView,
ScrollView,
FlatList,
TouchableOpacity,
} from 'react-native';
import RNCalendarEvents from 'react-native-calendar-events';
import DatePicker from 'react-native-date-picker';
import { openDatabase } from 'react-native-sqlite-storage';
const db = openDatabase({
name: "calendar",
});
const Main = ({ navigation }) => {
const [eventTitle, setEventTile] = React.useState('');
const [eventLocation, setEventLocation] = React.useState('');
const [date, setDate] = React.useState(new Date());
const [open, setOpen] = React.useState(false);
const [dateValue, setdateValue] = React.useState('');
const [name, setName] = useState();
const [location, setLocation] = useState();
const [time, setTime] = useState();
const [id, setId] = useState();
const [categories, setCategories] = useState([]);
const addCategory = () => {
//if (!category||!adddescription||!adddata)
if (name.length == 0 || location.length == 0 || time.length == 0) {
alert("Enter category");
return false;
}
useEffect(async () => {
//let interval = setInterval(() => setTime(1), 1000)
await createTables();
await getCategories();
// return () => {
// clearInterval(interval);
// }
}, []);
React.useEffect(() => {
RNCalendarEvents.requestPermissions()
.then(res => {
console.log('Premission Response', res);
})
.catch(error => {
console.log(error);
});
}, []);
const createEvent = () => {
const newDate = new Date(date);
newDate.setHours(newDate.getHours() + 2);
RNCalendarEvents.saveEvent(eventTitle, {
calendarId: '3',
startDate: date.toISOString(),
endDate: newDate.toISOString(),
location: eventLocation
}).then((value) => {
console.log('Event Id--->', value);
setId(value)
console.log("Event Data-->", name);
console.log("Event Data-->", location);
console.log("Event time-->", time);
}).catch((error) => {
console.log(' Did Not work Threw an error --->', error)
})
}
function submit() {
const newDate = new Date(date);
newDate.setHours(newDate.getHours() + 2);
RNCalendarEvents.saveEvent(eventTitle, {
calendarId: '3',
startDate: date.toISOString(),
endDate: newDate.toISOString(),
location: eventLocation
}).then((value) => {
console.log('Event Id--->', value);
setId(value)
console.log("Event Data-->", name);
console.log("Event Data-->", location);
console.log("Event time-->", time);
addCategory();
// navigation.navigate("RootScreen")
}).catch((error) => {
console.log(' Did Not work Threw an error --->', error)
})
}
const renderItem = ({ item }) => (
<Text style={styles.title}>{name}</Text>
);
return (
<View style={styles.container}>
<ScrollView>
<View style={styles.mainContainer}>
<View style={styles.singleElement}>
<View style={styles.dateInputContainer}>
<TextInput value={dateValue} style={styles.dateInput} />
<TouchableOpacity
style={styles.dateIcon}
onPress={() => setOpen(true)}>
<Text> SELECT DATA/TIME </Text>
</TouchableOpacity>
<DatePicker
modal
open={open}
date={date}
onConfirm={date => {
var currentdate = new Date(date);
var datetime =
+currentdate.getDate() +
'/' +
(currentdate.getMonth() + 1) +
'/' +
currentdate.getFullYear() +
' - ' +
currentdate.getHours() +
':' +
currentdate.getMinutes();
setOpen(false);
setDate(date);
setTime(date);
setdateValue(datetime.toString());
}}
minimumDate={new Date()}
onCancel={() => {
setOpen(false);
}}
/>
</View>
</View>
</View>
<TouchableOpacity
style={{
flex: 2,
padding: 25,
height: 72,
justifyContent: 'center',
alignSelf: 'center',
}}
onPress={() => submit()}
>
<Text> Save Event </Text>
</TouchableOpacity>
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f4f4fc',
marginTop: 50,
},
mainContainer: {
display: 'flex',
flexDirection: 'row',
padding: 10,
},
singleElement: {
display: 'flex',
flex: 4,
flexDirection: 'column',
},
textInputContainer: {
display: 'flex',
flexDirection: 'column',
padding: 15,
backgroundColor: '#fff',
borderRadius: 15,
marginBottom: 1,
},
dateInputContainer: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
padding: 15,
borderRadius: 15,
marginBottom: 1,
margin: 2,
},
dateIcon: {
padding: 10,
},
});
export default Main;
This will help you
for some reason
const manipResult = await ImageManipulator.manipulate(
image,
[{ resize: { width: 640, height: 480 } }],
{ format: 'jpg' }
);
returns [TypeError: undefined is not an object (evaluating '_expo.ImageManipulator.manipulate')]
which is weird because it worked one time and then this started to be returned by react native whenever it runs this line of code. so basically what im trying to do is resize the image and then send it to an api but for some reason it won't work and keeps giving this error even though data.uri isn't undefined
whole code
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, Image } from 'react-native';
import Constants from 'expo-constants';
import { Camera, CameraType } from 'expo-camera';
import * as MediaLibrary from 'expo-media-library';
import { MaterialIcons } from '#expo/vector-icons';
import Button from './src/components/Button';
import axios from 'axios'
import { Buffer } from "buffer";
import * as FS from "expo-file-system";
import { ImageManipulator } from 'expo';
export default function App() {
const [hasCameraPermission, setHasCameraPermission] = useState(null);
const [image, setImage] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const [flash, setFlash] = useState(Camera.Constants.FlashMode.off);
const cameraRef = useRef(null);
useEffect(() => {
(async () => {
MediaLibrary.requestPermissionsAsync();
const cameraStatus = await Camera.requestCameraPermissionsAsync();
setHasCameraPermission(cameraStatus.status === 'granted');
})();
}, []);
const takePicture = async () => {
if (cameraRef) {
try {
const data = await cameraRef.current.takePictureAsync();
console.log(data);
const manipResult = await ImageManipulator.manipulate(
data.uri,
[{ resize: { width: 640, height: 480 } }],
{ format: 'jpg' }
);
setImage(manipResult0);
} catch (error) {
console.log(error);
}
}
};
uriToBase64 = async (uri) => {
let base64 = await FS.readAsStringAsync(uri, {
encoding: FS.EncodingType.Base64,
});
return base64;
};
toServer = async (mediaFile) => {
const url = "api url";
let response = await FS.uploadAsync(url, mediaFile.uri, {
headers: {
"content-type": "image/jpeg",
},
httpMethod: "POST",
uploadType: FS.FileSystemUploadType.BINARY_CONTENT,
});
console.log(response);
};
const savePicture = async () => {
if(image) {
try {
const asset= await MediaLibrary.createAssetAsync(image);
await toServer({
type:"image",
base64: uriToBase64(image),
uri: image,
});
setImage(null);
console.log('saved successfully');
} catch (error) {
console.log(error);
}
}
};
if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
{!image ? (
<Camera
style={styles.camera}
type={type}
ref={cameraRef}
flashMode={flash}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 30,
}}
>
<Button
title=""
icon="retweet"
onPress={() => {
setType(
type === CameraType.back ? CameraType.front : CameraType.back
);
}}
/>
<Button
onPress={() =>
setFlash(
flash === Camera.Constants.FlashMode.off
? Camera.Constants.FlashMode.on
: Camera.Constants.FlashMode.off
)
}
icon="flash"
color={flash === Camera.Constants.FlashMode.off ? 'gray' : '#fff'}
/>
</View>
</Camera>
) : (
<Image source={{ uri: image }} style={styles.camera} />
)}
<View style={styles.controls}>
{image ? (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 50,
}}
>
<Button
title="Re-take"
onPress={() => setImage(null)}
icon="retweet"
/>
<Button title="Save" onPress={savePicture} icon="check" />
</View>
) : (
<Button title="Take a picture" onPress={takePicture} icon="camera" />
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#000',
padding: 8,
},
controls: {
flex: 0.5,
},
button: {
height: 40,
borderRadius: 6,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontWeight: 'bold',
fontSize: 16,
color: '#E9730F',
marginLeft: 10,
},
camera: {
flex: 5,
borderRadius: 20,
},
topControls: {
flex: 1,
},
});
Here I have used Redux to manage state but i am getting this type of Error: TypeError: navigation.state.params.AddBlack is not a function. (In 'navigation.state.params.AddBlack({
noteTitle: noteTitle,
noteValue: noteValue
})', 'navigation.state.params.AddBlack' is undefined)
ViewBlacks.js
import React from 'react'
import { Button, StyleSheet, View, FlatList } from 'react-native'
import { Text, FAB, List } from 'react-native-paper'
import { useSelector, useDispatch } from 'react-redux'
import { addblack, deleteblack } from '../redux/notesApp'
import Header from '../components/Header'
function ViewBlacks({ navigation }) {
const blacks = useSelector(state => state.number)
const dispatch = useDispatch()
const addBlack = black => dispatch(addblack(black))
const deleteBlack = id => dispatch(deleteblack(id))
return (
<>
<Header titleText='Simple Note Taker' />
<Button title="Go back" onPress={() => navigation.goBack()} />
<View style={styles.container}>
{blacks.length === 0 ? (
<View style={styles.titleContainer}>
<Text style={styles.title}>You do not have any notes</Text>
</View>
) : (
<FlatList
data={blacks}
renderItem={({ item }) => (
<List.Item
title={item.black.noteTitle}
description={item.black.noteValue}
descriptionNumberOfLines={1}
titleStyle={styles.listTitle}
onPress={() => deleteBlack(item.id)}
/>
)}
keyExtractor={item => item.id.toString()}
/>
)}
<FAB
style={styles.fab}
small
icon='plus'
label='Add new note'
onPress={() =>
navigation.navigate('AddBlacks', {
addBlack
})
}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 10,
paddingVertical: 20
},
titleContainer: {
alignItems: 'center',
justifyContent: 'center',
flex: 1
},
title: {
fontSize: 20
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 10
},
listTitle: {
fontSize: 20
}
})
export default ViewBlacks
AddBlack.js
import React, { useState } from 'react'
import { View, StyleSheet } from 'react-native'
import { IconButton, TextInput, FAB } from 'react-native-paper'
import Header from '../components/Header'
function AddBlack({ navigation }) {
const [noteTitle, setNoteTitle] = useState('')
const [noteValue, setNoteValue] = useState('')
function onSaveNote() {
navigation.state.params.addBlack({ noteTitle, noteValue })
navigation.goBack()
}
return (
<>
<Header titleText='Add a new note' />
<IconButton
icon='close'
size={25}
color='white'
onPress={() => navigation.goBack()}
style={styles.iconButton}
/>
<View style={styles.container}>
<TextInput
label='Add Title Here'
value={noteTitle}
mode='outlined'
onChangeText={setNoteTitle}
style={styles.title}
/>
<TextInput
label='Add Note Here'
value={noteValue}
onChangeText={setNoteValue}
mode='flat'
multiline={true}
style={styles.text}
scrollEnabled={true}
returnKeyType='done'
blurOnSubmit={true}
/>
<FAB
style={styles.fab}
small
icon='check'
disabled={noteTitle == '' ? true : false}
onPress={() => onSaveNote()}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingHorizontal: 20,
paddingVertical: 20
},
iconButton: {
backgroundColor: 'rgba(46, 113, 102, 0.8)',
position: 'absolute',
right: 0,
top: 40,
margin: 10
},
title: {
fontSize: 24,
marginBottom: 20
},
text: {
height: 300,
fontSize: 16
},
fab: {
position: 'absolute',
margin: 20,
right: 0,
bottom: 0
}
})
export default AddBlack
notesReducer.js
import remove from 'lodash.remove'
// Action Types
export const ADD_NOTE = 'ADD_NOTE'
export const DELETE_NOTE = 'DELETE_NOTE'
export const ADD_BLACK = 'ADD_BLACK'
export const DELETE_BLACK = 'DELETE_BLACK'
// Action Creators
let noteID = 0
let blackID = 0
export function addnote(note) {
return {
type: ADD_NOTE,
id: noteID++,
note
}
}
export function deletenote(id) {
return {
type: DELETE_NOTE,
payload: id
}
}
export function addblack(black) {
return {
type: ADD_BLACK,
id: blackID++,
black
}
}
export function deleteblack(id) {
return {
type: DELETE_BLACK,
payload: id
}
}
// reducer
const INITIAL_STATE = {
note: [], // for holds notes
number: [] // for holds numbers
};
function notesReducer(state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_NOTE:
return {
...state,
note: [
...state.note,
{
id: action.id,
note: action.note
}
]
};
case DELETE_NOTE:
const note = remove(state.note, obj => obj.id != action.payload);
return {...state, note};
case ADD_BLACK:
return {
...state,
number: [
...state.number,
{
id: action.id,
number: action.number
}
]
};
case DELETE_BLACK:
const number = remove(state.number, obj => obj.id != action.payload);
return {...state, number}
default:
return state
}
}
export default notesReducer
"objects are not valid as a react child (found: object with keys {date, events}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of View."
So I have kind of a cascade of method calls. I'm retrieving dates with events inside of those. It feels like I'm doing this correctly, but am getting the above error. I've tried setting createFragment on places, but still getting the error. Here's the code:
import React, { Component } from 'react';
import {
AppRegistry,
Text,
View,
ScrollView,
RefreshControl,
StyleSheet,
Dimensions,
TextInput,
Linking,
TouchableNativeFeedback
} from 'react-native';
var _ = require('lodash');
var {width, height} = Dimensions.get('window');
var renderif = require('render-if');
var createFragment = require('react-addons-create-fragment');
var IMAGES_PER_ROW = 1
class FunInATL extends Component {
constructor(props) {
super(props);
this.state = {
currentScreenWidth: width,
currentScreenHeight: height,
dates: [],
boxIndex: 0,
showBox: false,
refreshing: false
};
}
handleRotation(event) {
if (!this.state) {
return;
}
var layout = event.nativeEvent.layout
this.state({currentScreenWidth: layout.width, currentScreenHeight: layout.height })
}
calculatedSize() {
var size = this.state.currentScreenWidth / IMAGES_PER_ROW
return {width: size}
}
renderRow(events) {
return events.map((events, i) => {
return (
<Image key={i} style={[this.getImageStyles(), styles.image, this.calculatedSize() ]} source={{uri: event.image}} />
)
})
}
openUrl(url) {
Linking.canOpenURL(url).then(supported => {
if (supported) {
Linking.openURL(url);
} else {
console.log('nope :: ' + url);
}
}).catch(err => console.error('An error occurred', err));
}
getImageStyles(featured, category) {
let options = {
borderColor: 'gold',
borderWidth: featured ? 1 : 0
}
if (!category) {
options.height = featured ? 250 : 125
}
return options;
}
_clickImage(event, index) {
if (event.title) {
let new_val = !this.state.showBox
this.setState({
dates: this.state.dates,
showBox: new_val,
boxIndex: new_val ? index : 0
});
}
}
componentDidMount() {
this.state = {
dates: [],
boxIndex: 0,
showBox: false,
refreshing: false
};
this.getApiData();
Linking.addEventListener('url', this.handleUrl);
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleUrl);
}
getApiData() {
var _this = this;
return fetch('https://www.funinatl.com/mobile2.php?v1')
.then(function(response) {
return response.json()
})
.then((responseJson) => {
var dates = createFragment(responseJson.events)
return;
let _this = this;
date.events.map((event, i) => (
date.events[i] = event
))
var datesData = [];
dates.map((date, i) => (
datesData.push({
date: i,
events: createFragment(date.events)
})
))
_this.setState({
dates: createFragment(datesData),
boxIndex: 0,
showBox: false
})
console.error(this.state);
})
.catch((error) => {
console.error(error);
})
.done();
}
renderDates() {
return this.state.dates.map((date) =>
(
<View>
<Text style={styles.dateHeader}>{ date.date }</Text>
<View>
{this.renderEvents(date.events)}
</View>
</View>
))
}
renderImage(event, index) {
if (this.state.showBox && this.state.boxIndex == index) {
return (
<View>
<TouchableNativeFeedback onPress={()=>this._clickImage(event, index)}>
<Image source={{ uri: event.image }} style={[styles.image, this.calculatedSize(), this.getImageStyles(event.featured), { height: 100 }]} />
</TouchableNativeFeedback>
<View style={{ flexDirection:'row', padding: 15 }}>
<Text style={styles.price}>{event.price}</Text>
<Text style={styles.time}>{event.time}</Text>
<TouchableNativeFeedback onPress={()=>this.openUrl(event.website)}>
<Text style={styles.btn}>Website</Text>
</TouchableNativeFeedback>
</View>
{renderif(event.venue)(
<TouchableNativeFeedback onPress={()=>this.openUrl(event.venue)}>
<Text style={styles.btn}>Venue</Text>
</TouchableNativeFeedback>
)}
</View>
)
} else {
return (
<View>
<TouchableNativeFeedback onPress={()=>this._clickImage(event, index)}>
<Image source={{ uri: event.image }} style={[styles.image, this.calculatedSize(), this.getImageStyles(event.featured)]} />
</TouchableNativeFeedback>
</View>
)
}
}
renderEvents(events) {
return events.map((event, i) =>
(
<View>
<Text style={[styles.eventCategory, this.getImageStyles(event.featured, true)]}>{event.category}</Text>
<View>
{this.renderImage(event, i)}
</View>
<Text style={[styles.eventTitle, this.getImageStyles(event.featured, true)]}>{event.title}</Text>
</View>
));
}
_onRefresh() {
this.setState({refreshing: true});
fetchData().then(() => {
this.setState({refreshing: false});
});
}
render() {
return (
<ScrollView onLayout={this.handleRotation} contentContainerStyle={styles.scrollView} refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
tintColor="#ff0000"
title="Loading..."
titleColor="#00ff00"
colors={['#ff0000', '#00ff00', '#0000ff']}
progressBackgroundColor="#ffff00"
/>
}>
<Text style={styles.header}>FunInATL</Text>
{this.renderDates()}
</ScrollView>
)
}
}
var styles = StyleSheet.create({
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
textAlign: 'center',
padding: 10
},
header: {
fontSize: 30,
fontWeight: 'bold',
padding: 20,
textAlign: 'center',
backgroundColor: '#000',
color: '#fff'
},
dateHeader: {
fontSize: 20,
fontWeight: 'bold',
padding: 20,
textAlign: 'left',
color: '#fff',
backgroundColor: '#283593'
},
eventCategory: {
backgroundColor: '#03a9f4',
textAlign: 'center',
color: '#ffffff',
padding: 3
},
eventTitle: {
borderTopWidth: 0,
textAlign: 'center',
fontWeight: 'bold',
padding: 3,
fontSize: 18,
},
image: {
},
btn: {
backgroundColor: 'green',
padding: 10,
color: '#fff',
textAlign: 'center',
flex: 1
},
price: {
marginLeft: 10,
fontSize: 16,
flex: 1
},
time: {
marginRight: 10,
fontSize: 16,
flex: 1,
width: 35
}
});
AppRegistry.registerComponent('FunInATL', () => FunInATL);
Thanks!
EDIT: Updated code per the map suggestion, still not working. complaining about {events} only now.
EDIT 2: Updated with FULL code.
The component's render helpers, such as renderDates(), are returning _.each(...). _.each() returns its first argument so this is why you are receiving the error.
To illustrate:
const myObject = { a: 1 };
_.each(myObject) === myObject // true
I recommend you use Array.prototype.map() instead:
return this.state.dates.map((date) => (
<View>...</View>
));
If you use arrow functions like I did in the example above, there's no need to save a reference to this. this in the body of the function passed to map() will be bound to the instance of the component. You can then call other helper methods such as getImageStyles() like this.getImageStyles(...).
This is not related to your original question but the getApiData() method will not work. You can replace the function in the chain that handles responseJson with something like:
(responseJson) => {
this.setState({
dates: Object.entries(responseJson.events).map(([date, { events }]) => ({
date,
events,
})),
boxIndex: 0,
showBox: false,
});
}
You also need to to remove the this.state = {...} in componentDidMount(). Notice the warning in the docs that indicates you should "NEVER mutate this.state directly".