How to change View Content On Click - React Native - reactjs

I've been trying to replace a view in React Native, but to no success. The app closes without errors whenever I try <TouchableOpacity onPress={() => {handleChangeMyView();}}> :
What am I doing wrong? How can I make it work?
Thank you all in advance.
import React, {
useState
} from 'react';
import {
SafeAreaView,
View,
TouchableOpacity,
} from 'react-native';
import MyInitialView from './MyInitialView';
const SiteContainer = () => {
let MyDynamicView = () => {
return (
<View></View>
);
};
const [MyDynamicViewArea, setMyDynamicViewArea] = useState(MyInitialView);
const handleChangeMyView = () => {
setMyDynamicViewArea(MyDynamicView);
};
return (
<SafeAreaView>
{MyDynamicViewArea}
<TouchableOpacity onPress={() => {handleChangeMyView();}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
);
};
export default SiteContainer;
MyInitialView :
import React from 'react';
import {
View
} from 'react-native';
export default function MyInitialView() {
return (
<View></View>
);
}

You can use boolean value for viewing MyInitialView using useState
const [toViewMyInitialView, setToViewMyInitialView] = useState(false);
and in handleChangeMyView function set the above value as true
const handleChangeMyView = () => {
setToViewMyInitialView(true);
};
And in the SiteContainer
<SafeAreaView style={styles.siteContainer}>
// here I don't know a way to display a component in react-native, so
// you need to display the component MyInitialView if the
// toViewMyInitialView is true and when toViewMyInitialView id false it
// display MyDynamicViewArea
{toViewMyInitialView && <MyInitialView/>}
{!toViewMyInitialView && <MyDynamicViewArea/>}
<TouchableOpacity onPress={() => {handleChangeMyView()}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>

Related

React native page keeps crashing, I can't see why

I'm making a react native app on Expo, but the whole app crashes everytime I try to get into this one page. This is my first time using react native, and I'm still a beginner to react, but I can't see what's causing the issue. The error I'm getting is Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it., but I can't see where
import { StyleSheet, Text, View, TouchableOpacity, ScrollView, TextInput } from 'react-native'
import React, { useState, useEffect } from 'react'
// import CartCard from '../Components/CartCard'
import ItemCard from '../Components/ItemCard'
const Cart = ({navigation}) => {
const [details, setDetails] = useState([])
useEffect(()=>{
getData()
}, [])
const getData = async() => {
try {
const getValues = await AsyncStorage.getItem('object')
if(getValues !== null){
console.log(JSON.parse(getValues))
setDetails(getValues)
// const objectValues = JSON.parse(getValues)
// setDetails(objectValues)
// getValues.forEach(object => {
// console.log("id:", object.id)
// setToyId(object.id)
// })
}
}catch(error){
console.log('getData didnt work')
}
}
const [cardholder, setCardholder] = useState('');
const [cardNumber, setCardNumber] = useState('');
const [expiryDate, setExpiryDate] = useState('');
const [cvc, setCvc] = useState('');
const [allItems, setAllItems] = useState(0);
const [total, setTotal] = useState(0)
const clearCart = () => {
console.log('cc')
}
const countAllItems = () => {
console.log('cai')
}
const countTotal = () => {
console.log('ct')
}
return (
<ScrollView style={{backgroundColor: 'white', height: '100%'}}>
<ItemCard />
<View>
<View style={styles.payment}>
<Text>Your Shopping Cart</Text>
<View>
<Text value={allItems} onChangeText={(value)=>{setAllItems(value)}}>Overall Items: {countAllItems}</Text>
<Text value={total} onChangeText={(value)=>{setTotal(value)}}>Total Price: ${countTotal}.00</Text>
</View>
</View>
<Text>Payment</Text>
<TextInput placeholder='Cardholder Name' style={styles.inputsLong} placeholderTextColor='black' value={cardholder} onChangeText={(value)=>setCardholder(value)}/>
<TextInput placeholder='Card Number' style={styles.inputsLong} placeholderTextColor='black' value={cardNumber} onChangeText={(value)=>setCardNumber(value)}/>
<View style={styles.shortForm}>
<TextInput placeholder='MM/YY' style={styles.inputsShort} placeholderTextColor='black' value={expiryDate} onChangeText={(value)=>setExpiryDate(value)} />
<TextInput placeholder='CVC' style={styles.inputsShort} placeholderTextColor='black' value={cvc} onChangeText={(value)=>setCvc(value)}/>
</View>
<View style={styles.buttonRow}>
<TouchableOpacity>
<Text style={styles.cancelButton} onPress={clearCart}>Cancel Order</Text>
</TouchableOpacity>
<TouchableOpacity>
<Text style={styles.orderButton} onPress={()=>navigation.navigate('ConfirmScreen')}>Place Order</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
)
}
export default Cart
const styles = StyleSheet.create({ // styles })
ItemCard component doesn't take any parameters yet because I'm having problems storing data and passing data between pages, but this is what the component looks like in its current state:
import { StyleSheet, Text, View, ScrollView } from 'react-native'
import React from 'react'
const ItemCard = () => {
return (
<ScrollView>
<View style={styles.itemSection}>
<View style={styles.card}></View>
</View>
</ScrollView>
)
}
export default ItemCard
const styles = StyleSheet.create({ // styles })
For this warning
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
you have to call the functions
eg. countTotal()
<Text value={total} onChangeText={(value)=>{setTotal(value)}}>Total Price: ${countTotal()}.00</Text>
if you are using onPress then like this
<Text style={styles.cancelButton} onPress={()=>clearCart()}>Cancel Order</Text>

How to change View content in React Native

I've been trying to replace a view in React Native, but to no success. The app closes without errors whenever I try <TouchableOpacity onPress={() => {handleChangeMyView();}}> :
What am I doing wrong? How can I make it work?
Thank you all in advance.
import React, {
useState
} from 'react';
import {
SafeAreaView,
View,
} from 'react-native';
import MyInitialView from './MyInitialView';
const SiteContainer = () => {
let MyDynamicView = () => {
return (
<View></View>
);
};
const [MyDynamicViewArea, setMyDynamicViewArea] = useState(MyInitialView);
const handleChangeMyView = () => {
setMyDynamicViewArea(MyDynamicView);
};
return (
<SafeAreaView style={styles.siteContainer}>
{MyDynamicViewArea}
<TouchableOpacity onPress={() => {handleChagnStaceMyView();}}>
<View>
<FontAwesome name="quote-left"></FontAwesome>
</View>
</TouchableOpacity>
</SafeAreaView>
);
};
export default SiteContainer;
MyInitialView :
import React from 'react';
import {
View
} from 'react-native';
export default function MyInitialView() {
return (
<View></View>
);
}
You have incorrect name of function in onPress of TouchableOpacity.
Change this
onPress={() => {handleChagnStaceMyView();}}
to
onPress={() => {handleChangeMyView();}}
you are calling wrong function <TouchableOpacity onPress={() => {handleChagnStaceMyView();}}>
make it right as <TouchableOpacity onPress={() => {handleChangeMyView();}}>
good luck
I wonder you are not getting error like handleChagnStaceMyView is not defined

Calling a custom hook with a parameter from a custom component

I have this custom hook I want to be executed when pressing a button inside a custom component
import { useDispatch } from 'react-redux';
import { useCallback } from 'react';
import { retireUserFromEvents } from '../../../redux/actions/Events';
export default function useDeleteAssistantToEvent() {
const dispatch = useDispatch();
const deleteAssistantToEvent = useCallback(userID => {
dispatch(retireUserFromEvents(userID));
}, [dispatch]);
return deleteAssistantToEvent;
}
I declare the hook on the screen where the custom component is:
import {
AttendantList
} from '../../../../components';
import useDeleteAssistantToEvent from '../../../../hooks/assistance/useDeleteAssistantToEvent';
export default function EventAssistantsView({ navigation }) {
const deleteAssistant = useDeleteAssistantToEvent();
return (
<SafeAreaProvider>
<SafeAreaView style={styles.safeAreaViewStyle}>
<View style={styles.mainViewStyle}>
<AttendantList
...
undoInvite={() => deleteAssistant}
/>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
And this is my custom component (AttendantList):
export default function AttendantList({ attendees, goToUserProfile, undoInvite, imHostOrCohost }) {
return (
<View style={styles.mainViewStyle}>
{attendees.length > 0 ? (
<FlatList
...
renderItem={({ item }) => (
<TouchableOpacity onPress={goToUserProfile()}>
<InviteCard
...
onPress={() => undoInvite(item.id)}
/>
</TouchableOpacity>
)}
/>
) : (
...
)}
</View>
);
}
ÌnviteCard is the button in question.
The problem is that, anytime I want to press the button, nothing happens. So, how can I pass the hook call to the custom component?

EXPO: Setting up react-native-action-sheet

Currently trying to setup react-native-action-sheet and getting an invalid hook call
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
I followed the example and wrapped my wrapped your top-level component with even when using hooks.
export default () => (
<ActionSheetProvider>>
<App />
</<ActionSheetProvider>>
);
Wondering if it's the way I set this up:
import { Linking } from 'react-native';
import { useActionSheet } from '#expo/react-native-action-sheet';
export const SideButton = () => {
const { showActionSheetWithOptions } = useActionSheet();
const cancelButtonIndex = 1;
const options = ['Email', 'Cancel'];
const title = 'Email Me';
const message = 'Let me know your issues';
return showActionSheetWithOptions(
{
options,
cancelButtonIndex,
title,
message,
},
(buttonIndex) => {
if (buttonIndex === 0) {
Linking.openURL('mailto:_____').catch();
} else {
return;
}
}
);
};
Or even how I call it here:
import { Linking, Text, TouchableOpacity, View } from 'react-native';
import { SideButton } from './utils/HelpPopUp';
const ButtonContainer = () => (
<TouchableOpacity>
<Text onPress={() => Linking.openURL('_MY_WEBSITE_').catch()}>Checkout my stuff</Text>
</TouchableOpacity>
);
const Menu = (props) => {
return (
<View>
<ButtonContainer />
</View>
);
};
export default Menu;
Sorry, my answer would be to suggest an alternative rather than answer your question and present the component I use myself. I did not use the package you mentioned in the topic, but I tried with a different package before, it does the same job. https://www.npmjs.com/package/react-native-actions-sheet
This is the custom component I used.
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
import ActionSheet from 'react-native-actions-sheet';;
const CustomActionSheet = React.forwardRef(({children, title}, ref) => {
return (
<ActionSheet
ref={ref}
headerAlwaysVisible={true}
containerStyle={[
styles.containerStyle,
{backgroundColor: '#FFF'},
]}
CustomHeaderComponent={
<View style={[styles.header, {backgroundColor: '#4ac'}]}>
<Text style={styles.title}>
{title}
</Text>
</View>
}>
{children}
</ActionSheet>
);
});
const styles = StyleSheet.create({
header: {
height: 50,
justifyContent: 'center',
padding: 5,
},
title: {
color: '#FFF',
fontSize: globalStyles.titleText.fontSize,
},
containerStyle: {
borderRadius: 0,
},
});
export default CustomActionSheet;
Usage:
import React, { createRef } from "react";
import {View, Text} from "react-native";
import CustomActionSheet from './CustomActionSheet';
const actionSheetRef = createRef();
const AnythingPage = () => {
return (
<View>
<Text onPress={() => actionSheetRef.current?.show()}>
Open Custom Sheet
</Text>
<CustomActionSheet ref={actionSheetRef} title={'Title'}>
<View>
<Text>Add anything in it.</Text>
</View>
</CustomActionSheet>
</View>
)
}
You can develop a structure that will be used in the whole application by going through these.

React navigation with hooks and header function - state is not updating

Trying to use react navigation with hooks and a button in the navigation header.
I can pass the handleShowModalLogin function to the navigation header and I can see the button is clicked, but the problem is the setShowLoginModal is not updating the showLoginModal state to true. Not sure why this is not working.
import React, { useState, useEffect, useLayoutEffect } from "react";
import {
Image,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
Button,
} from 'react-native';
import LoginModal from './users/LoginModal';
const HomeScreen = ({navigation}, props) => {
const [showLoginModal, setShowLoginModal] = useState(false);
const handleShowModalLogin = (value) => {
console.log("showLoginModal button clicked: ", value)
if(value === "on"){
setShowLoginModal(true);
}else{
setShowLoginModal(false);
}
}
useEffect(() => {
console.log('navigation handler set with showLoginModal set:', showLoginModal)
navigation.setParams({ handleShowModalLogin: handleShowModalLogin });
}, []);
useEffect(() => {
console.log("showLoginModal value changed: ", showLoginModal), [showLoginModal]
})
return (
<View style={styles.container}>
<LoginModal showLoginModal={showLoginModal} />
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}>
</ScrollView>
</View>
);
};
HomeScreen.navigationOptions = ({ navigation }) => ({
title: "Home",
headerRight: (
<View style={styles.headerComContainer}>
<Button
onPress={() => {
navigation.getParam('handleShowModalLogin')('on')
}}
title="Login"
color="#841584"
accessibilityLabel="Login" />
</View>
)
});
Here's the login modal component.
import React, { useState } from "react";
import { Text, TouchableOpacity, View, ScrollView } from "react-native";
import Modal from 'modal-enhanced-react-native-web';
export default function LoginModal(props){
const [visibleModal, setModalVisible] = useState(props.showLoginModal);
return (
<View>
<Modal
isVisible={visibleModal}
onBackdropPress={() => setModalVisible(false)}
>
<View>
<Text>Hello!</Text>
<TouchableOpacity onPress={() => setModalVisible(false)}>
<View>
<Text>Close</Text>
</View>
</TouchableOpacity>
</View>
</Modal>
</View>
);
}
const [visibleModal, setModalVisible] = useState(props.showLoginModal);
This code in the LoginModal creates a state, who's initial initial value is props.showLoginModal. After that initial value though, there's no connection with the prop. Changing the prop later will not cause the state to change.
You seem to be trying to mix having LoginModal be a controlled component (where a parent handles the logic, and then controls it through props) and an uncontrolled component (where the component manages its own state). Instead, i'd recommend picking one or the other.
From the fact that you're trying to control it externally, it looks like you want to create a controlled component. So your login modal will need modification to have additional props to notify the parent of the clicks. Perhaps an "onBackdropPressed" and an "onClosePressed", as in:
export default function LoginModal(props){
return (
<View>
<Modal
isVisible={props.showLoginModal}
onBackdropPress={() => props.onBackdropPressed()}
>
<View>
<Text>Hello!</Text>
<TouchableOpacity onPress={() => props.onClosePressed()>
<View>
<Text>Close</Text>
</View>
</TouchableOpacity>
</View>
</Modal>
</View>
);
}
Don't forget to modify the home screen to pass those additional props in, as in:
<LoginModal
showLoginModal={showLoginModal}
onBackdropPressed={() => setShowLoginModal(false)}
onClosePressed={() => setShowLoginModal(false)}
/>

Resources