How to use useState in other functions React Native - javascript

I have a question about react native. I want to write a username in the textInput here
function logIn({ navigation }) {
const [username, setUsername] = useState('');
return (
<View style={{ backgroundColor: "white"}} >
<View>
<TextInput style={styles.input} placeholder='username' placeholderTextColor='white' textAlign='center' onChangeText={(val) => setUsername(val)} />
</View>
<View>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
</View>
</View>
);
}
and then I want to see the username i wrote on this screen. Of course this doesnt work because it shows Cant find variable username so is there a way to fix this?
function HomeScreen({ navigation }) {
return(
<View style={{ flex:1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Welcome {username}</Text>
</View>
);
}

You need to structure your state in a way that it is accessible to the components that need it. React likes you to have state in a component thats 'higher' in the tree than the components that need it, you can look at https://reactjs.org/docs/lifting-state-up.html for this.
Otherwise you could use the Context API or a 'global' store like Redux.
Logged in user data is a good candidate for the likes of Context or Redux, that way you will have access to the likes of username in any part of the application that is within your Context / Redux provider that provides the logged in data (or whatever other global data you may have)

You colud pass parameters to Home screen using navigation.navigate function in this way:
function logIn({ navigation }) {
const [username, setUsername] = useState('');
return (
<View style={{ backgroundColor: "white"}} >
<View>
<TextInput style={styles.input} placeholder='username' placeholderTextColor='white' textAlign='center' onChangeText={(val) => setUsername(val)} />
</View>
<View>
<Button title="Go to Home" onPress={() => navigation.navigate('Home', {username: username})} />
</View>
</View>
);
}
Then in HomeScreen:
function HomeScreen({ navigation, route }) {
return(
<View style={{ flex:1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Welcome {route.params.username}</Text>
</View>
);
}

Related

How to pass up nested state and avoid useCallback in react native

I have a parent and nest child component hierarchy of QuestionsAndAnswersScreen -> QuestionInput -> QuestionSelector -> AnswerSelector. I need to pass the question and answer object back up to the QuestionAndAnswerScreen in order to show it on the view. However I cannot find a way without going into deep nested callbacks.
Here is my code for the QuestionAnswerScreen and AnswerSelector:
function QuestionsAndAnswers() {
const {shell, body} = styles;
return (
<View style={shell}>
<SignUpHeader title="Add your answers" page={5}/>
<View style={body}>
{qAndA[1] ? <Answer question={qAndA[1].question} answer={qAndA[1].answer}/> : <QuestionInput />}
{qAndA[2] ? <Answer question={qAndA[2].question} answer={qAndA[2].answer}/> : <QuestionInput />}
{qAndA[3] ? <Answer question={qAndA[3].question} answer={qAndA[3].answer}/> : <QuestionInput />}
</View>
<SignUpFooter
title={`Questions\n& Answers`}
buttonTitle={"Done"}
disabled={false}
route="QuestionsAndAnswers"
/>
</View>
);
}
function AnswerInput(props: AnswerInputProps) {
const {question, visible, answerModalVisible} = props;
const {pickAnAnswer, doneButton, answerTextInput, questionStyle, shell, buttonText} = styles;
const [modalVisible, setModalVisible] = useState(visible)
const [answer, setAnswer] = useState('');
const navigation = useNavigation();
useEffect(() => {
setModalVisible(visible)
}, [visible])
function answerQuestion() {
setModalVisible(false);
navigation.navigate('QuestionsAndAnswers');
}
return (
<View>
<Modal style={shell}
isVisible={modalVisible}
onBackdropPress={() => {
setModalVisible(false);
answerModalVisible(false);
}}
>
<View>
<Text style={pickAnAnswer}>Add answer</Text>
</View>
<View>
<Text style={questionStyle}>{question}</Text>
</View>
<View>
<TextInput
style={answerTextInput}
placeholder="Add your answer here..."
placeholderTextColor="#878787"
onChangeText={(text: string) => setAnswer(text)}
/>
<View style={{alignItems: 'flex-end', marginTop: 44}}>
<TouchableOpacity style={doneButton} onPress={() => answerQuestion()}>
<Text style={buttonText}>
Done
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
}
As you can see I get my Question and Answer in the AnswerInput but then need to navigate back to the main screen in order to display them. Any help would be great thanks :)

React Native: I can't set a TextInput value from a 'child' screen

I am working in React Native and I want to set a value in a non-editable TextInput. The value is written on a screen that I am navigating to. Meaning; "parent" screen has the empty input -> I navigate to a "child" screen in which I can enter the value in another TextInput. When I have done that I want to press "OK" and go back to the "parent" screen where the value is displayed.
I have read the documentation as thoroughly as I could, but I still can't get it to work. I can set the value in the "child" screen, but the value is not updated when I navigate back to the parent.
Parent screen
Disregard the code related to equipment, since it will assimilate the barcode logic
import React, { useState } from 'react'
import { Text, TouchableOpacity, View, Image, TextInput } from 'react-native'
import styles from './styles';
import { IMAGE } from '../../constants/Images'
import { CustomHeader } from '../../CustomHeader'
export default function SamplingScreen({ navigation, route }) {
//const [barcodeData, setBarcodeData] = useState('32231321')
const [equipmentID, setEquipmentID] = useState('')
//Guarding against undefined value
const barcode = route.params?.barcode ?? 'Barcode'
return (
<View style={styles.container}>
<CustomHeader title="Sample Oil" navigation={navigation} isHome={true} ></CustomHeader>
<View style={styles.contentContainer}>
<Image
style={styles.logo}
source={IMAGE.ICON_LOGO}
/>
<Text>Send an oil sample for analysis</Text>
<Text>Start by linking a bottle with its barcode</Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('BottleID')} /*barcodeData={setBarcodeData}*/ >
<Text style={styles.buttonText} >Link Bottle</Text>
</TouchableOpacity>
<Text>Please link the equipment from which the sample was taken</Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('EquipmentID')} equipmentID={setEquipmentID} >
<Text style={styles.buttonText} >Link Equipment</Text>
</TouchableOpacity>
<Text>This is the bottle barcode</Text>
<TextInput
editable={false}
style={styles.input}
defaultValue={barcode}
value={barcode}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<Text>This is the equipment barcode</Text>
<TextInput
editable={false}
style={styles.input}
defaultValue={equipmentID}
value={equipmentID}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<TouchableOpacity style={styles.button}>
<Text style={styles.buttonText}>Accept</Text>
</TouchableOpacity>
</View>
</View>
)
}
Child screen
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, TextInput } from 'react-native';
import { CustomHeader } from '../../../CustomHeader'
import styles from './styles'
export default function SetBottleIDScreen({ navigation, route }) {
const [barcodeData, setBarcodeData] = useState('')
console.log(barcodeData)
return (
<View style={styles.container} >
<CustomHeader title="Bottle ID" isHome={false} navigation={navigation} ></CustomHeader>
<Text style={{ marginTop: 30, marginBottom: 30 }} > Set barcode for sampling bottle </Text>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Camera')}>
<Text style={styles.buttonText}>Scan Barcode</Text>
</TouchableOpacity>
<Text style={{ marginTop: 60, marginBottom: 10 }} >Insert Barcode</Text>
<TextInput
style={styles.input}
placeholder='Barcode'
placeholderTextColor="#aaaaaa"
onChangeText={(text) => setBarcodeData(text)}
value={barcodeData}
underlineColorAndroid="transparent"
autoCapitalize="none">
</TextInput>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Sampling', { screen: 'Sampling', params: { barcode: barcodeData }, merge: true })}>
<Text style={styles.buttonText} >OK</Text>
</TouchableOpacity>
</View>
);
}
I am using React Navigation 5.x. I am pretty sure that the value has to be parsed as a parameter with route, but something isn't working as intended.
I solved the issue.
The syntax for setting the parameters were wrong.
It should look like this in stead:
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Sampling', { barcode: barcodeData })}>
<Text style={styles.buttonText} >OK</Text>
</TouchableOpacity>

React Native TextInput Value persist when Tab is changed

I have encountered a weird issue in the newest react native where the value in the text input in a component remains when a tab is switched.
I can't figure what is going on and I thought it should re-render when tab is changed but it doesn't.
Here's my code
app.js
export default function App() {
const [tab, setTab] = useState("TAB1")
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
style={{ borderRadius: 5, borderWidth: 1, marginRight: 5, padding: 20 }}
onPress={() => setTab("TAB1")}
>
<Text>Tab 1</Text>
</TouchableOpacity>
<TouchableOpacity
style={{ borderRadius: 5, borderWidth: 1, padding: 20}}
onPress={() => setTab("TAB2")}
>
<Text>Tab 2</Text>
</TouchableOpacity>
</View>
<View style={{ marginTop: 20}}>
{
tab === "TAB1" ? (
<View>
<InputComponent tab={tab} />
</View>
) : (
<View>
<InputComponent tab={tab} />
</View>
)
}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
marginTop: 100,
padding: 10
},
});
inputcomponent.js
export function InputComponent({ tab }) {
const [value, setValue] = useState("");
return (
<View>
<Text>{tab}</Text>
<TextInput placeholder="INPUT HERE" value={value} onChangeText={setValue}/>
</View>
)
}
It seems like the input component re-renders but the text input within it doesn't change.
Demo Issue
This is such a good question. This is because we are importing it once and passing it to two different components. It changes the tab but uses the same textinput state because they are using the same key.
To fix this pass in the key prop so React knows that tab changed:
{
tab === "TAB1" ? (
<View>
<InputComponent key={1} tab={tab} />
</View>
) : (
<View>
<InputComponent key={2} tab={tab} />
</View>
)
}
Snack: https://snack.expo.io/mVVLb9uId
Read about keys: https://reactjs.org/docs/lists-and-keys.html#keys

Updating informations from modal-React native

On my react native app I display information that I fetched from the server this way:
So when I click update profil, I display a modal with text input on it in order to give the user the opportunity to change the information of his profile. The modal look like this:
Now I already created a Fetch Post function that, when I click on the button update it sends static information to the server and the modal closes. but the profile page doesn't refresh until I get out of it and come back.
My question is: whats the best way to get the values from the textinputs, send them through post. and refresh the screen after the modal closes?. Should i use formik?
Here is a look at my code:
export default function MprofilScreen({ navigation }) {
const [modalVisible, setModalVisible] = useState(false);
const [Data, setData] = useState([]);
useEffect(() => {
fetch('******')
.then((response) => response.json())
.then((res) => {
console.log("repooooonse")
console.log(res)
setData(res)
})
.done();
}, []);
return (
<View style={{ flex: 1, backgroundColor: 'white' }} >
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
}}>
<View style={styles.modalView}>
<TouchableOpacity
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>close</Text>
</TouchableOpacity>
<ScrollView>
<Text style={styles.text}>Nom:</Text>
<TextInput style={styles.text_input} placeholder="nom" />
....
<Text style={styles.text}>Ville :</Text>
<TextInput style={styles.text_input} placeholder="Ville " />
<TouchableOpacity
style={{ ...styles.openButton, backgroundColor: "#2196F3" }}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<Text style={styles.textStyle}>Delete</Text>
</TouchableOpacity>
</ScrollView>
</View>
</Modal>
<TouchableOpacity style={styles.btn}
onPress={() => {
setModalVisible(true);
}}>
<Text style={{ color: 'white', fontSize: 15 }}> Update profil</Text>
</TouchableOpacity>
<View >
<View style={styles.main_container}>
<Text style={styles.text}>Nom:</Text>
<Text style={styles.text1}>{Data.nom}</Text>
</View>
.....
<View style={styles.main_container}>
<Text style={styles.text}>Ville:</Text>
<Text style={styles.text1}> {Data.ville}</Text>
</View>
</View>
</View>
);
}
I'm new to react native and I'll appreciate your help!
I'll assume you have the fetching details in componentDidMount of that profile page, and since modal also resides in it, so page doesnt refresh. What you can do is call that function again on modalClose.
suppose you have,
getDetails = () => {
.... fetch details
}
and in componentDidMount you call like :
componentDidmount(){
this.getDetails();
}
So same you can call on modalClose the same function after updating it.
onModalClose = () => {
this.getDetails()
}
hope its clear.feel free for doubtys

Error: Looks like you nested a 'Navigation Container' inside another when calling a GoToButton in child file React Navigation 5

I created a GoToButton as advised by React Navigation v5 to move from one child screen to another
function GoToButton({ screenName }) {
const navigation = useNavigation();
return (
<TouchableOpacity
title={`${screenName}`}
onPress={() => navigation.navigate(screenName)} style={styles.buttonLogin}>
<Text style={{color: '#ffcc00', fontWeight: 'bold'}}>Start!</Text>
</TouchableOpacity>
);
}
I wanted to move from the login screen which was imported inside of the function:
function LoginScreen({navigation}) {
return (
<View>
<Login />
<View style={{alignContent:'center' , alignItems:'center'}}>
<GoToButton screenName="TabNavigator" />
</View>
</View>
);
}
To the TabNavigatorScreen:
function TabNavigatorScreen({ navigation }) {
return (
<TabNavigator/>
);
}
When I place the reference to the GoToButton like this, the reference works:
function LoginScreen({navigation}) {
return (
<View>
<Login /> //imported earlier from the file Login.js
<View style={{alignContent:'center' , alignItems:'center'}}>
<GoToButton screenName="TabNavigator" /> //next to the imported Login
</View>
</View>
);
}
But my goal is to place the GoToButton inside of the Login.js as shown:
import GoToButton from '../navigation/SwitchNavigator' class Login extends React.Component {
login = () => {
this.props.login(this.props.email)
}
render() {
return (
<View style={{ position: 'absolute', justifyContent: 'center', alignItems: 'center', flex: 1, justifyContents: "flex-end", width: screenWidth, height: screenHeight, backgroundColor: 'white', }}>
<View style={styles.box}>
<TextInput value={this.props.user} style={styles.textarea} onChangeText={input => this.props.updateEmail(input)}
placeholder='Email'/>
<TextInput value={this.props.user} style={styles.textarea} onChangeText={input => this.props.updatePassword(input)}
placeholder='Password' />
<GoToButton screenName="TabNavigator" onPress={() => this.login()}/>
</View>
</View>
);
}
}
Unfortunately, this results in the error: ooks like you nested a 'Navigation Container' inside another. How do I solve this problem?

Categories

Resources