How to change View content in 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,
} 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

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 On Click - 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,
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>

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?

react native navigation - update list in screen on add/update/delete items

I am building a mobile app using react native. I am using the stack navigator from react-native-navigation library.
the stack has two screens, the first screen ItemsListScreen displays a list of items with add button, clicking the add button navigates to the second screen AddItemScreen which displays some inputs for the item with a save button. clicking the save button will navigate back to the list screen.
Items are saved currently on a local SQLite database, but in future will be saved on a server.
ItemsListScreen.js
import React, { useEffect, useState, useContext } from "react";
import { Button, Image, Platform, StyleSheet, View, TouchableOpacity } from "react-native";
import { ScrollView } from "react-native-gesture-handler";
import { Ionicons } from "#expo/vector-icons";
import DatabaseContext from "../db/DatabaseContext";
export default function ItemsListScreen({ navigation }) {
const db = useContext(DatabaseContext);
const [items, setItems] = useState([]);
useEffect(() => {
navigation.setOptions({
headerRight: () => {
return (
<TouchableOpacity activeOpacity={0.5} style={{ paddingRight: 10 }} onPress={() => navigation.navigate("AddItem")}>
<Ionicons name="md-add" size={30} />
</TouchableOpacity>
);
},
});
db.getItems().then((data) => {
setItems(data);
});
}, []);
return (
<View style={styles.container}>
<ScrollView style={styles.container} contentContainerStyle={styles.contentContainer}>
{items.map((item, index) => (
<View key={index} style={styles.item}>
<Text style={styles.subSection}>{item.title}</Text>
</View>
))}
</ScrollView>
</View>
);
}
AddItemScreen.js
import React, { useState, useEffect, useContext } from "react";
import { StyleSheet, View, Dimensions, TextInput, ScrollView, TouchableOpacity, Picker, Switch } from "react-native";
import DateTimePicker from "#react-native-community/datetimepicker";
import { Ionicons } from "#expo/vector-icons";
import DatabaseContext from "../db/DatabaseContext";
export default function AddItemScreen({ navigation }) {
const db = useContext(DatabaseContext);
const [item, setItem] = useState({
title: "",
description: "",
// more properties
});
const saveItem = () => {
db.saveItem(item);
navigation.navigate("ItemsList");
};
useEffect(() => {
navigation.setOptions({
headerRight: () => {
return (
<TouchableOpacity activeOpacity={0.5} style={{ paddingRight: 10 }} onPress={saveItem}>
<Ionicons name="md-save" size={30} />
</TouchableOpacity>
);
},
});
}, [item]);
return (
<View style={styles.scene}>
<ScrollView>
<Text style={styles.label}>Title</Text>
<TextInput style={styles.field} value={item.title} onChangeText={(text) => setItem((prevState) => ({ ...prevState, title: text }))} />
<Text style={styles.label}>Description</Text>
<TextInput style={styles.field} value={item.description} onChangeText={(text) => setItem((prevState) => ({ ...prevState, description: text }))} />
{/* more inputes */}
</ScrollView>
</View>
);
}
My problem is that the list on ItemsListScreen is not updated when a new item is added. I need to reload the app to get the list updated.
I tried to remove the second parameter (the empty array) from the useEffect in ItemsListScreen, it works but I think it is a bad solution as it keeps reading from the db on each re-render.
How can I refresh the list whenever the user navigates back to the list screen? I thought the useEffect will be executed whenever the screen is activated but it seems not.
You will be resolved by adding navigation focus listener to ItemsListScreen.js. Replace your useEffet in this way
useEffect(() => {
navigation.setOptions({
headerRight: () => {
return (
<TouchableOpacity activeOpacity={0.5} style={{ paddingRight: 10 }} onPress={() => navigation.navigate("AddItem")}>
<Ionicons name="md-add" size={30} />
</TouchableOpacity>
);
},
});
const unsubscribe = navigation.addListener('focus', () => {
db.getItems().then((data) => {
setItems(data);
});
});
return unsubscribe;
}, []);

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