I dont understand how to hide and show Components dependet und a state. I came up with the following code, but i think its wrong, because the UI isnt being update after i press the "login" button. Is there a general way to do this? I also aks myself how to handle changing between "Dialogs". For example i want that when a Button is clicked, that the current Dialog is closed and the target Dialog is renderd. How could i do this?
import React from 'react';
import { ImageBackground, StyleSheet, TouchableOpacity, Text, View, TextInput} from 'react-native';
function WelcomeScreen(props) {
var loginDialog = {
visible: false
};
var signUpDialog = {
visible: false
};
var welcomeDialog = {
visible: true
};
const login = loginDialog.visible ? (
<View style={styles.loginDialog}>
<TextInput style={styles.input}/>
</View>
) : null;
const signup = signUpDialog.visible ? (
<View style={styles.signUpDialog}>
<TextInput style={styles.input}/>
</View>
) : null;
const welcome = welcomeDialog.visible ? (
<View style={styles.buttonContainer}>
<TouchableOpacity onPress={changeState("login")}style={[styles.button, styles.login]}>
<Text style={styles.text}>Log In</Text>
</TouchableOpacity>
<TouchableOpacity onPress={changeState("signup")} style={[styles.button, styles.signUp]}>
<Text style={styles.text}>Sign Up</Text>
</TouchableOpacity>
</View>
) : null;
function changeState(mode){
if(mode === "login"){
console.log("Yes");
welcomeDialog.visible = false;
loginDialog.visible = true;
}else if(mode === "signup"){
welcomeDialog.visible = false;
signUpDialog.visible = true;
}
}
return (
<ImageBackground style={styles.background}
source={require('../assets/welcome_background.jpg')}>
{login}
{signup}
{welcome}
</ImageBackground>
);
}
export default WelcomeScreen;
Seems like you are new to react you should read about state https://reactjs.org/docs/state-and-lifecycle.html.
You should use useState in functional component or setState in class component also I really recomend to use third party library for dialogs/modals.
https://github.com/mmazzarolo/react-native-dialog
https://github.com/react-native-modal/react-native-modal
import React, {useState} from 'react';
import { ImageBackground, StyleSheet, TouchableOpacity, Text, View, TextInput} from 'react-native';
function WelcomeScreen(props) {
const [loginDialog,setLoginDialog] = useState(false);
const [signUpDialog ,setSignUpDialog ] = useState(false);
const [welcomeDialog ,setWelcomeDialog ] = useState(false);
const login = loginDialog ? (
<View style={styles.loginDialog}>
<TextInput style={styles.input}/>
</View>
) : null;
const signup = signUpDialog? (
<View style={styles.signUpDialog}>
<TextInput style={styles.input}/>
</View>
) : null;
const welcome = welcomeDialog? (
<View style={styles.buttonContainer}>
<TouchableOpacity onPress={changeState("login")}style={[styles.button, styles.login]}>
<Text style={styles.text}>Log In</Text>
</TouchableOpacity>
<TouchableOpacity onPress={changeState("signup")} style={[styles.button, styles.signUp]}>
<Text style={styles.text}>Sign Up</Text>
</TouchableOpacity>
</View>
) : null;
const changeState = (mode) => {
if(mode === "login"){
console.log("Yes");
setWelcomeDialog(false);
setLoginDialog(true);
}else if(mode === "signup"){
setWelcomeDialog(false);
setSignUpDialog(true);
}
}
return (
<ImageBackground style={styles.background}
source={require('../assets/welcome_background.jpg')}>
{login}
{signup}
{welcome}
</ImageBackground>
);
}
export default WelcomeScreen;
Related
I'm pretty new to React Native and don't have the most experience with javascript so although this may be very simple I have no idea what to do. I have a class Component which acts like a popup in my app. It pops up on press of a touchable opacity and displays a little menu. I am trying to get the id of the button that is pressed on that menu and send it back to the functional component main screen (where the touchable opacity to open the menu is). I can get the id of the button but I'm struggling to get this data out of the popup and back into my main screen(functional component)
Here is my Code for the Main Screen:
import { StyleSheet, Text, View, Image,TouchableOpacity} from 'react-native'
import React,{useState} from 'react'
import tw, { create } from 'twrnc';
import Map from "../components/Map"
import { SafeAreaView } from 'react-native-safe-area-context';
import { BottomPopup } from '../components/popup';
import { selectTrucks} from '../slices/navSlice';
import { useSelector } from 'react-redux';
const Logistics = () => {
const Trucks = useSelector(selectTrucks);
let popupRef = React.createRef()
const onShowPopup = () => {
popupRef.show()
}
const onClosePopup = () => {
popupRef.close()
}
return (
<View style={{flex:1,resizeMode:'contain'}}>
<View style={tw`h-12/16`}>
<Map/>
</View>
<TouchableOpacity onPress={onShowPopup} style={{top:'-68%'}}>
<Image
source = {{uri: "https://icon-library.com/images/app-menu-icon/app-menu-icon-21.jpg" }}
style = {{width:'20%', height:40,resizeMode:'contain'}}
/>
<Text style={{color:'black',paddingLeft:2,fontSize: 26,fontWeight:"bold",top:-37,left:70}}>Truck {}</Text>
</TouchableOpacity>
<BottomPopup
title = "Select Option"
ref = {(target)=> popupRef = target}
onTouchOutside={onClosePopup}
data={Trucks.TrucksInfo}
/>
<SafeAreaView style={{top:'-13%'}}>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 36,fontWeight:"bold"}}>123 Elmo Street</Text>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 24,fontWeight:"bold"}}>L4L 6L8, Mississauga, Ontario</Text>
<Text style={{color:'darkgreen',paddingLeft:2,fontSize: 18,fontWeight:"bold"}}>Phone Number: 416-749-6857{'\n'}Client: Bobby Jeff{'\n'}Order Number: 7187181{'\n'}Packing Slip Number: 882929</Text>
<Text style={{color:'black',fontSize: 18,paddingLeft:2}}>Customer Notified: Yes at 2:32 PM</Text>
</SafeAreaView>
</View>
)
}
export default Logistics
const styles = StyleSheet.create({})
And Here is the code for the class component popup:
import { Modal,Dimensions,TouchableWithoutFeedback,StyleSheet,View,Text,FlatList,TouchableOpacity} from "react-native";
import React from "react";
import { useNavigation } from '#react-navigation/native';
import Logistics from "../screens/Logistics";
const deviceHeight = Dimensions.get('window').height
export class BottomPopup extends React.Component {
constructor(props){
super(props)
this.state = {
show:false
}
}
show = () => {
this.setState({show:true})
}
close = () => {
this.setState({show:false})
}
renderOutsideTouchable(onTouch) {
const view = <View style = {{flex:1,width:'100%'}}/>
if (!onTouch) return view
return (
<TouchableWithoutFeedback onPress={onTouch} style={{flex:1,width:'100%'}}>
{view}
</TouchableWithoutFeedback>
)
}
renderTitle = () => {
const {title} = this.props
return (
<View style={{alignItems:'center'}}>
<Text style={{
color:'#182E44',
fontSize:25,
fontWeight:'500',
marginTop:15,
marginBottom:30,
}}>
{title}
</Text>
</View>
)
}
renderContent = () => {
const {data} = this.props
return (
<View>
<FlatList
style = {{marginBottom:130}}
showsVerticalScrollIndicator = {false}
data={data}
renderItem={this.renderItem}
extraData={data}
keyExtractor={(item,index)=>index.toString()}
ItemSeparatorComponent={this.renderSeparator}
contentContainerStyle={{
paddingBottom:40
}}
/>
</View>
)
}
renderItem = ({item}) => {
return(
<TouchableOpacity
onPress={() => {this.close(),console.log(item.id)}}
>
<View style = {{height:50,flex:1,alignItems:'flex-start',justifyContent:'center',marginLeft:20}}>
<Text style={{fontSize:18,fontWeight:'normal',color:"#182E44"}}>{item.name}</Text>
</View>
</TouchableOpacity>
)
}
renderSeparator = () => {
return(
<View
style={{
opacity:0.1,
backgroundColor:'#182E44',
height:1
}}
/>
)
}
render() {
let {show} = this.state
const {onTouchOutside,title} = this.props
return (
<Modal
animationType={"fade"}
transparent={true}
visible={show}
onRequestClose={this.close}
>
<View style={{flex:1, backgroundColor:"#000000AA",justifyContent:'flex-end'}}>
{this.renderOutsideTouchable(onTouchOutside)}
<View style={{
backgroundColor:'#FFFFFF',
width:'100%',
paddingHorizontal:10,
maxHeight:deviceHeight*0.4}}
>
{this.renderTitle()}
{this.renderContent()}
</View>
</View>
</Modal>
)
}
}
The console log in the render item function gets me the number i need i just need to get this number out and back into my logistics screen
What you can do is like onTouchOutside you can pass getId function as props which will return id.
I don`t have much experience with class component. So I have add sample code in functional component. You can refer this
const MainComponent = ()=>{
const getIdFunc = (id)=>{
//You will get id here
}
return(<View>
{/* pass function here */}
<PopUpComponent getIdFunc={getIdFunc}/>
</View>)
}
const PopUpComponent = (props)=>{
return(<TouchableOpacity
onPress={()=>{
//call function by passing id here
props.getIdFunc(id)
}}
>
</TouchableOpacity>)
}
I have an array of data stored in a JSON file. It has ID, title and description. Now I have listed out the titles in my ReactNative app. I want to display the content of each title on a modal. How can I do that?
Below is my code where the modal will come up, but the description won't appear on the modal. Instead it gives an error that it's not defined.
import { StatusBar } from "expo-status-bar";
import React, { useState } from "react";
import {
Modal,
Platform,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
} from "react-native";
export default function App() {
const data = require("./dummyData.json");
let modalData = [];
const [showStanzas, SetshowStanzas] = useState(false);
const onpressHandler = function (a, b) {
modalData = data[b];
SetshowStanzas(true);
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.headingView}>
<Text style={styles.heading}></Text>
</View>
<ScrollView>
<View style={styles.container2}>
<View style={styles.container3}>
{data.map((datas, id) => {
return (
<View key={id}>
<Text
style={styles.hymnTitle}
onPress={() => {
onpressHandler(true, id);
}}
>
{datas.id}. {""}
{datas.title}{" "}
</Text>
</View>
);
})}
<Modal
animationType={"slide"}
visible={showStanzas}
onRequestClose={() => SetshowStanzas(false)}
>
<View>
<Text style={styles.desc}> {modalData.description} </Text>
</View>
</Modal>
</View>
</View>
</ScrollView>
</SafeAreaView>
);
}
Migrate the local variable modalData to a React state
const [mobileData, setMobileData] = useState();
Then store the selected index data on the on onpressHandler
const onpressHandler = function (a, b) {
setMobileData(data[b]);
SetshowStanzas(true);
};
Your modal code should work afterwards
Here's the function-
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
I want to display the variable 'messages' separately in my app, how would I do that? 'messages' variable needs to be displayed within the default react native 'Text' component. I have written down 'messages' below within Text component but currently it's not displaying anything (since it is within function) -
import React, { useState, useEffect, useReducer } from 'react';
import { View, Text, StyleSheet, FlatList, ActivityIndicator, Keyboard} from 'react-native';
import { Searchbar } from 'react-native-paper';
import { theme } from '../theme';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { apiStateReducer } from '../reducers/ApiStateReducer';
import CognitensorEndpoints from '../services/network/CognitensorEndpoints';
import DefaultView from '../components/default/DefaultView';
import DashboardListCard from '../components/DashboardListCard';
const AppHeader = ({
scene,
previous,
navigation,
searchIconVisible = false,
}) => {
const [dashboards, dispatchDashboards] = useReducer(apiStateReducer, {
data: [],
isLoading: true,
isError: false,
});
const [filtered, setFiltered] = useState([]);
const setLoading = (value) => {
const messages = dashboards.data.message.filter((item) => {
const title = item.dashboardTitle || item.dashboardName;
return title.toLowerCase().startsWith(value.toLowerCase());
});
setFiltered(messages);
console.log(filtered);
};
const dropShadowStyle = styles.dropShadow;
const toggleSearchVisibility = () => {
navigation.navigate('Search');
};
useEffect(() => {
CognitensorEndpoints.getDashboardList({
dispatchReducer: dispatchDashboards,
});
}, []);
return (
<>
<View style={styles.header}>
<View style={styles.headerLeftIcon}>
<TouchableOpacity onPress={navigation.pop}>
{previous ? (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.visible}
/>
) : (
<MaterialIcons
name="chevron-left"
size={24}
style={styles.invisible}
/>
)}
</TouchableOpacity>
</View>
<Text style={styles.headerText}>
{messages}
</Text>
<View style={styles.headerRightIconContainer}>
{searchIconVisible ? (
<TouchableOpacity
style={[styles.headerRightIcon, dropShadowStyle]}
onPress={toggleSearchVisibility}>
<MaterialIcons name="search" size={24} style={styles.visible} />
</TouchableOpacity>
) : (
<View style={styles.invisible} />
)}
</View>
</View>
</>
);
};
If your messages variable is an array you can map it
{messages.map((message, key)=>(
<Text style={styles.headerText}>
{message.dashboardName}
</Text>
))}
Since your messages variable is stored in 'filtered' state, you can map it by doing this:
{filtered.map((item, index) => <Text key={index}>{item.dashboardName}<Text>)}
When I run this inside a function, and click either one of the touchableOpacity I have to save the code for it to check the id number then return the correct outcome
const pressHandler = (id) => {
if (id == 1) {
Pressedinfo = <View>
<Text>one</Text>
</View>
} else if (id = 2) {
Pressedinfo = <View>
<Text>two</Text>
</View>
}
}
in the return (view):
<TouchableOpacity onPress={() => pressHandler(1)}>
<Text style={Styles.Text1}>1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => pressHandler(2)}>
<Text style={Styles.Text1}>2</Text>
</TouchableOpacity>
{Pressedinfo}
You need to use state. Move your react element out of the function and just manipulate the string in state.
In your constructor create a state:
constructor(props){
super(props);
this.state = {textString: ''}
}
const pressHandler = (id) => {
if (id === 1) {
this.setState({textString : 'one'})
}
else if(id === 2) {
this.setState({textString : 'two'})
}
}
For the template:
<TouchableOpacity onPress={() => pressHandler(1)}>
<Text style={Styles.Text1}>1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => pressHandler(2)}>
<Text style={Styles.Text1}>2</Text>
</TouchableOpacity>
<View>
<Text>{this.state.textString}</Text>
</View>
This is how I would try.
import React, { Component, useState } from 'react';
import { View, TouchableOpacity, Text } from 'react-native';
const App = () => {
const [Pressedinfo, setPressedInfo] = useState(null)
const pressHandler = (id) => {
if (id == 1) {
setPressedInfo(<View><Text>one</Text></View>)
} else if (id = 2) {
setPressedInfo(<View><Text>two</Text></View>)
}
}
return (
<View>
<TouchableOpacity onPress={() => pressHandler(1)}>
<Text style={Styles.Text1}>1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => pressHandler(2)}>
<Text style={Styles.Text1}>2</Text>
</TouchableOpacity>
{Pressedinfo}
</View>
)
}
use this.state method to change the components without re rendering the page.
I'm pretty new to Native React. I just went through the Expo tutorial and I am trying to make a Button that can consolidate the TouchableOpacity and Text into one component for re-usability.
I keep getting "Invariant Violation: Button(): Nothing was returned from render." I also referenced here.
Stylesheet is not in code below, not a concern.
Thanks!
import React from 'react';
import { Image, Platform, StyleSheet, Text, View, TouchableOpacity } from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import * as Sharing from 'expo-sharing';
function Button(props)
{
return
(
<TouchableOpacity
onPress={props.command} style = {styles.button}>
<Text style={styles.buttonText}>{props.t}</Text>
</TouchableOpacity>
);
}
export default function App() {
const [selectedImage, setSelectedImage] = React.useState(null);
let openImagePickerAsync = async() => {
let permissionResult = await ImagePicker.requestCameraRollPermissionsAsync();
if (permissionResult.granted === false)
{
alert("Permission to access camera roll is required!");
return;
}
let pickerResult = await ImagePicker.launchImageLibraryAsync();
if (pickerResult.cancelled === true)
{
return;
}
setSelectedImage({localUri:pickerResult.uri});
};
let openShareDialogAsync = async() => {
if (!(await Sharing.isAvailableAsync()))
{
alert(`The image is available for sharing at: ${selectedImage.remoteUri}`);
return;
}
Sharing.shareAsync(selectedImage.localUri);
};
if (selectedImage !== null)
{
return(
<View style={styles.container}>
<Image
source ={{uri:selectedImage.localUri}}
style={styles.thumbnail}
/>
<TouchableOpacity onPress={openShareDialogAsync} style={styles.button}>
<Text style={styles.buttonText}>Share this photo</Text>
</TouchableOpacity>
</View>
);
}
return (
<View style={styles.container}>
<Image source={{uri: "https://i.imgur.com/TkIrScD.png"}} style={styles.logo} />
<Text style = {styles.instructions}>
To share a photo from your phone with a friends, just press the button below!
</Text>
<Button command = {openImagePickerAsync} t = "Pick a photo"/>
{/*
<TouchableOpacity
onPress={openImagePickerAsync} style = {styles.button}>
<Text style={styles.buttonText}>Pick a photo</Text>
</TouchableOpacity>
*/}
</View>
);
}
Nothing wrong with your code only thing is your return statement. When you place the opening bracket in the next line it will not return anything and your actual component code will be unreachable as it will be considered as a separate block. Just change it to the code below.
function Button(props) {
return (
<TouchableOpacity onPress={props.command} style={styles.button}>
<Text style={styles.buttonText}>{props.t}</Text>
</TouchableOpacity>
);
}