React Native CustomAlert does not work inside onPress - javascript

I'm facing a weird problem. In my react native app I have customAlert, which shows if the statement is false, currently it shows only the console.
I tried testing and showing my CustomAlert but not inside onPress it works fine like the image below. but inside onPress does not work. What am I missing here?
import CustomAlert from '../components/CustomAlert';
const [modalVisible, setModalVisible] = useState(false);
<View style={{ marginTop: `30%`, alignItems: 'center' }}>
<GoogleSigninButton
style={{ width: 252, height: 58 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={() => {
if (fingerprint === true) {
googleLogin();
}
else {
console.log("Alert should pop up");
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Please enable your Touch ID/PIN to your device'}
buttons={[{
text: 'Ok',
func: () => { console.log('Yes Pressed') }
}]}
/>
}
}
}
/>
</View>

You could try moving your <CustomAlert> outside of the <GoogleSignInButton> and then display the <CustomAlert> conditionally based on your modalVisible state variable:
import CustomAlert from '../components/CustomAlert';
const [modalVisible, setModalVisible] = useState(false);
<View style={{ marginTop: `30%`, alignItems: 'center' }}>
<GoogleSigninButton
style={{ width: 252, height: 58 }}
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={() => {
if (fingerprint === true) {
googleLogin();
}
else {
console.log("Alert should pop up");
setModalVisible(true);
}
}
}
/>
<CustomAlert
modalVisible={modalVisible}
setModalVisible={setModalVisible}
title={'Message'}
message={'Please enable your Touch ID/PIN to your device'}
buttons={[{
text: 'Ok',
func: () => { console.log('Yes Pressed') }
}]}
/>
</View>
Notice that inside the else branch we call setModalVisible(true) which will set modalVisible to true. Then modalVisible gets passed as a prop to <CustomAlert>, which should tell the modal to render (assuming it is set up properly).

Related

React native <View> doesn't work inside if statment

function sumbit_Login(val, val1, nav) {
const we = val.length
const we1 = val1.length
if (we <= 15) {
alert('Invaild Email')
return (
<View style={{ width: 50000, height: 50000, backgroundColor: 'red' }}>
</View>
)
}
if (we1 <= 5) {
alert('Invaild Password')
return 0;
}
else {
nav.navigate('Main')
}
// I use it here out the function (inside another function)
<View style={{ marginBottom: 10, width: "80%", marginLeft: '10%', marginTop: '-8%' }}>
<Button
title="Login"
onPress={() => sumbit_Login(value, value1, navigation)}
/>
</View>
The view doesn't work in if statement anyone have another way or solve the problem i use the function inside a button but the 'View' inside return doesn't work (I don't get any error.)
You're not using the View anywhere in the component tree, try to trace your code, you're calling a function onPress, which is a callback and isn't really inside your render hierarchy, if I understand your use case correctly, you're doing this the wrong way..
The way that should be done is to have a state control the visibility of the view when you want to render it and when you don't, here's an example:
function SomeComponent({ navigation }) {
// Create a state for the visiblity
const [visible, setVisible] = useState(false)
function onSubmit(val, val1) {
const we = val.length
const we1 = val1.length
if (we <= 15) {
alert('Invaild Email')
// Set visiblity to true in order to show the View
setVisible(true)
return
}
if (we1 <= 5) {
alert('Invaild Password')
return;
}
else {
navigation.navigate('Main')
}
}
return (
<View style={{ marginBottom: 10, width: "80%", marginLeft: '10%', marginTop: '-8%' }}>
<Button
title="Login"
onPress={() => sumbit_Login(value, value1, navigation)}
/>
{
// Conditionally render the View
visible && <View style={{ width: 50000, height: 50000, backgroundColor: 'red' }}>
}
</View>
)
}
I suggest you read more docs about react and react native, dos and don'ts, and the best practices for dealing with the lifecycle
Hope you find this helpful

Lottie file animation play when selected (Expo)

I want it to play only when the card is selected, if the card is not selected it simply displays the lottie file but nothing is being played. Right now I get an error of cannot read property 'play' of null. When I remove the animationPress() and get the file to run it also start at the mentioned initialSegment that I'm passing into it.
What am I doing wrong here?
My card that the Lottie file is in:
const animation = useRef(null);
const animationPress = () => {
animation.current.play();
}
return(
{filteredData.map((item, index) => {
return (
<>
<TouchableOpacity onPress={() => setSelected(item), animationPress()}>
<View style={[{ alignItems: 'center' }, selected.id == item.id ? { paddingTop: 10 } : { paddingTop: 20 }]}>
<CardioCard style={selected.id == item.id ? { backgroundColor: 'green', fontFamily: 'ssb_SemiBold' } : {}} >
<CardItem style={[styles.card, selected.id == item.id ? { backgroundColor: 'green' } : {}]}>
<Text>
< LottieView
ref={animation}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={true}
loop={true}
style={{ width: 100, height: 100 }} />
</Text>
</CardItem>
</CardioCard>
<Text style={[{ fontSize: 18, color: 'hsl(98, 0%, 11%)', paddingLeft: 15 }, selected.id == item.id ? { fontFamily: 'ssb_SemiBold' } : {}]}>{item.name}</Text>
</View>
</TouchableOpacity>
</>
)
})}
...
)
Edit
I also tried to do useState for the autoplay and loop button so they would be false but when the button is pressed it would turn true but the animation wouldn't load even after the button press.
const [playAnimation, setPlayAnimation] = useState(false);
<TouchableOpacity onPress={() => setPlayAnimation(true)}>
<LottieView
source={require('../../assets/images/heartbeat.json')}
autoPlay={playAnimation}
loop={playAnimation}
style={{ width: 100, height: 100 }}
/>
</TouchableOpacity>
this is driving me nuts and idk what to do anymore.
I'm new to react-native but I guess it's like react. Not sure to correctly understand the issue.
In this case, shouldn't you use animation.current instead of animation as your lottieView ref? or at least ensure that your ref animation is defined (not null) so that the container can be mounted even if not launched, this is also for your animationPress function. Also you should disable the autoPlay I guess (since you want to trigger the animation with a button).
< LottieView
ref={animation.current}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={false}
loop={true}
style={{ width: 100, height: 100 }} />
or
{animation && < LottieView
ref={animation}
source={require('../../assets/images/heartbeat.json')}
initialSegment={68,135}
autoPlay={false}
loop={true}
style={{ width: 100, height: 100 }} />}
And of course
const animationPress = () => {
if(animation?.current) {
animation.current.play();
}
}

position: "absolute" with Button is not working on IOS | React Native

I have a hamburger button that triggers a side menu in a mobile app. The button doesn't respond when position is set to absolute. I have seen similar issue which suggest wrapping the button with <View> </View> and setting its position to absolute, however this didn't work in my case. The button doesn't respond when being clicked on IOS. Android works perfectly fine
Code Snippet:
import React, { useState, useEffect } from "react";
import { View, StyleSheet } from "react-native";
import Hamburger from "#psyycker/rn-animated-hamburger";
function HamburgerIcon({ navigation }) {
const [status, setStatus] = useState(false);
useEffect(() => {
const unsubscribe = navigation.addListener("drawerClose", (e) => {
setStatus(false);
});
return unsubscribe;
}, [navigation]);
async function callBack() {
setStatus(true);
navigation.toggleDrawer();
}
return (
<View style={styles.btnContainer}>
<View style={{ marginTop: 40, marginLeft: 20 }}>
<Hamburger
active={status}
type="spinArrow"
color="blue"
onPress={() => callBack()}
></Hamburger>
</View>
</View>
);
}
const styles = StyleSheet.create({
btnContainer: {
position: "absolute",
flex: 1,
},
});
Solved by wrapping around SafeAreaView and setting zIndex to a high number.
<SafeAreaView style={{ position: "absolute", margin: 40, marginLeft: 20, zIndex:99999 }}>
<Hamburger active={status}
type="spinArrow"
color="blue"
onPress={() => callBack()}
>
</Hamburger>
</SafeAreaView>

Expo / RN - Get face landmarks

I have a working code based on simple examples from the official documentation:
https://docs.expo.io/versions/latest/sdk/camera and https://docs.expo.io/versions/latest/sdk/facedetector.
It is said "While detecting faces, FaceDetector will emit object events of the following shape..."
But I don't understand how I can access the values of these objects. Tried all possible combinations - no success. What I am doing wrong? Can somebody help please?
The function "handleFacesDetected" is invoked while a face is detected but can't access the data.
This is the code:
import React from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Camera, Permissions, FaceDetector } from 'expo';
export default class CameraExample extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentWillMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
handleFacesDetected(){
// it gets here while the face is detected. how to access the data?
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera
style={{ flex: 1 }}
type={this.state.type}
onFacesDetected={this.handleFacesDetected}
faceDetectorSettings={{
mode: FaceDetector.Constants.Mode.accurate,
detectLandmarks: FaceDetector.Constants.Mode.all,
runClassifications: FaceDetector.Constants.Mode.all,
}}
>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type: this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Text
style={{ fontSize: 18, marginBottom: 10, color: 'white' }}>
{' '}Flip{' '}
</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
Use this
handleFacesDetected = async ({ faces }) => {
if(faces.length === 1){
this.setState({ face: true });
}
}

Rendering Child Component in React Native

I am using React Native and React Navigation to build a simple app.
I have got the basic structure working with stub state but I am having problem with changing state via callback and re-render.
In my screen, I have simple start button
`<View style={styles.buttonContainer}>
<TouchableOpacity
style={[myStyles.buttonStyle, { backgroundColor: color }]}
onPress={() => handlePress(button.title)}
>
<Text style={myStyles.textStyle}>{button.title}</Text>
</TouchableOpacity>
</View>`
Problem:
After I update my parent Component state, my child component does not instantly render to match the state change. I understood React will re-render all child components when parent state is changed?
Instead, I have to move back to previous screen and navigate again to my button screen to see that the button's color and text has changed correctly.
I've read about requiring a componentWillReceiveProps(nextProps) handler but I am not sure how to use it. I put a console.log('nextProps', nextProps) inside but it does not get fired.
From navigation perspective, the Root component is on index[0] and my button view is at index[3] so it's the 3rd screen from the root.
EDIT 1: Added Code
myButton screen:
export class TeamsScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: `${navigation.state.params.game.name}: Select Team`,
headerTintColor: 'white',
headerStyle: {
backgroundColor: 'black',
},
headerVisible: true
})
componentWillReceiveProps(nextProps) {
console.log('nextProps', nextProps);
}
render() {
const { navigate, setParams } = this.props.navigation;
const { game, player, setGameState } = this.props.navigation.state.params;
const color = game.status === 'Start' ? 'green' : 'red';
const index = game.indexOf(player);
const status = game.status;
console.log('index', index);
console.log('status', status);
return (
<View style={styles.container}>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[myStyles.buttonStyle, { backgroundColor: color }]}
onPress={() => setGameState(index, status)}
>
<Text style={myStyles.textStyle}>{game.status}</Text>
</TouchableOpacity>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={() => navigate('ChangeDriverScreen', { team, game })}
title='Change Driver'
/>
</View>
<View style={{ marginTop: 40, marginBottom: 20 }}>
<Text style={{ fontSize: 16, color: 'white', alignSelf: 'center' }}>Teams</Text>
</View>
<View style={{ height: 250 }}>
<FlatList
data={player.teams}
renderItem={({item}) =>
<View style={styles.buttonContainer}>
<Button
onPress={() => navigate('TeamSelectedStartScreen', { team: item })}
title={item.name}
/>
</View>}
keyExtractor={item => item.name}
/>
</View>
<Image
style={{ alignSelf: 'center', justifyContent: 'flex-end', height: 75, width: 250, resizeMode: 'stretch'}}
source={require('./images/icons/playerPlaceholder.png')}
/>
</View>
)}}
Then the onPress function that is called back:
setGameState = (gameIndex, status) => {
console.log('setGameState', gameIndex, status);
console.log('gameStateBefore', this.state.game);
const newGameState = this.state.game.map(t => {
console.log(this.state.game.indexOf(t));
if (this.state.game.indexOf(t) === gameIndex) {
const newStatus = status === 'Start' ? 'Stop' : 'Start';
t.status = newStatus; /*eslint no-param-reassign: "off"*/
console.log('inside if', t.status);
console.log('inside if game', t);
return t;
}
return t;
});
console.log('new Game State', newGameState);
this.setState(() => ({
game: newGameState
}));
}
So the setState method works (as re-navigating back to screen 3 shows the correct state but core question is how to get immediate re-render of screen 3 when setState is called from Screen 0.

Categories