React native button need twice click to change state - react-native

when i click on "Show Element" button, I want change state to true
and when i click on "Hide Element" button, I want change state to false
but when i click on "Show Element" button at first time it don't change to true and there is need i click on button second time for change state to true. and it's same when i click on "Hide Element" button
here is my code:
import * as React from 'react';
import { View, Text, StyleSheet, Platform, AsyncStorage, TouchableHighlight, ScrollView, SafeAreaView, Button } from 'react-native'
class Base extends React.Component {
constructor(props) {
super(props);
this.state = {
isForShowVar: true
}
}
render() {
return(
<View>
<Button
style={{marginTop:50, width:150}}
title="Hide Element"
onPress={()=>{ alert(this.state.isForShowVar); this.setState({isForShowVar: false}); }}
/>
<Button
style={{marginTop:50, width:150}}
title="Show Element"
onPress={()=>{ alert(this.state.isForShowVar); this.setState({isForShowVar: true}); }}
/>
</View>
)
}
}
export default Base;
you can test code in here
how can change state when i click on button at first time?
Thanks

Ciao, this happens because you read isForShowVar before set. Anyway also if you move alert after this.setState you got the old value because this.setState is async. But you can use this.setState callback like this:
this.setState({isForShowVar: true}, () => {
alert(this.state.isForShowVar);
});
Here your code modified.

Related

How elevate the alert in react native-paper?

I want to shown an alert but my alert make to my app down scroll like this
alert image
i would like show that alert on the center and elevate it.
i tried with this css, but does not worked nothing
const styles = StyleSheet.create({
elevatedElement: {
zIndex: 3000000,
elevation: 3000000,
},
})
this is my code of the alert
import React, { useState } from 'react'
import { View } from 'react-native';
import { Button, Paragraph, Dialog, Portal, Provider } from 'react-native-paper';
const Alert = ({ show, setShow }) => {
return (
<Provider>
<View>
<Portal>
<Dialog visible={show} >
<Dialog.Title>Alert</Dialog.Title>
<Dialog.Content>
<Paragraph>This is simple dialog</Paragraph>
</Dialog.Content>
<Dialog.Actions>
<Button onPress={setShow}>Done</Button>
</Dialog.Actions>
</Dialog>
</Portal>
</View>
</Provider>
);
};
export default Alert;
and i am using that component like this
return (
<><Alert show={true} />
<Background>
<RightButton goRight={logout} />
<Logo />
</Background>
</>
)
According to the documentation for the Portal usage:
Portal allows rendering a component at a different place in the parent tree. You can use it to render content that should appear above other elements, similar to Modal. It requires a Portal. Host component to be rendered somewhere in the parent tree
So if you want to render the Portal on top of other elements like a modal you should use the Portal.Host:
**Note:**Try to implement thePortal component as the first element of Alert component without using the View element as below:
import { Portal } from 'react-native-paper';
// rest of the codes ...
return (
<Portal.Host>
<Dialog visible={show} >
<Dialog.Title>Alert</Dialog.Title>
<Dialog.Content>
<Paragraph>This is simple dialog</Paragraph>
</Dialog.Content>
<Dialog.Actions>
<Button onPress={setShow}>Done</Button>
</Dialog.Actions>
</Dialog>
</Portal.Host>
);
No need to set the zIndex or elevation style properties for this component.

How can we create a react-native component which can be displayed with .show() method

I am looking for pointers where I can start from.
I want to create a react native feedback form which can be displayed with .show method.
for eg:
export class FeedbackComponent extends React.component{
show() {
// define this method in a way so that can be called from outside as FeedbackComponent.show()
// which eventually create a new screen with below rendered View
}
render (){
return <View>Feedback Form</View>
}
}
I should be able to use this Component in any other component as
import FeedbackComponent from './FeedbackComponent'
new FeedbackComponent.show()
I would always start with considering the application state. UI in React is updated whenever the State of our components changes.
In your case I would have to think of the parent context in which your feedback form will need to be displayed. In its simplest form, this context will likely be a parent screen-component within which your FeedbackForm component is either shown or hidden.
I've made a Snack of a simple implementation you can find it here: https://snack.expo.io/#stephos_/show-feedback-form
In my case, the App component is the parent screen-component within which we need to render or not render a FeedbackForm Component.
So I would start with adding the relevant state property to the App (parent screen) component like so:
state = {
feedbackFormVisible : false
}
I would then define a method within the same parent class in order to toggle the state when we need to like so:
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
This handler takes in the previous state in our parent component and toggles the value of the feedbackFormVisible property (i.e. from false to true).
In my case, I call this handler every time we press a Button component like so:
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
You could however trigger the same handler and update the state of the parent component in any other way (i.e. after a timer expires or after a specific scroll point is passed).
The App Component's render method will then decide if the FeedbackForm component should be displayed based on the value of the feedbackFormVisible in our App Component's state. We achieve this by wrapping our FeedbackForm component within an Elvis Conditional within the render method which will return the the appropriate UI (i.e. either with a visible feedback form or not):
{ this.state.feedbackFormVisible ? () : null}
Below the full App component code:
import * as React from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import FeedbackForm from './components/FeedbackForm';
export default class App extends React.Component {
state = {
feedbackFormVisible : false
}
handleFeedbackFormVisibility = () => this.setState(prevState => ({feedbackFormVisible:!prevState.feedbackFormVisible}))
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the App Parent Component
</Text>
{
this.state.feedbackFormVisible ?
(<FeedbackForm />)
: null
}
<Button title="Give Feedback" onPress={this.handleFeedbackFormVisibility}/>
</View>
);
}
}
And below the Feedback Component code (Notice that the shown/hidden logic is actually handled in the parent component not in here):
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
export default class FeedbackForm extends React.Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.paragraph}>
This is the feedback form!
</Text>
</View>
);
}
}

React Native | Why is my function running immediately, rather than just onPress?

I am just starting to grasp props in react native so I am hoping that this is a simple solution.
I want the state of the form to update to bring the user to the next page in the form and I want the state of the response to update as well - both when the user presses the button component (onPress).
However, what I'm seeing when I console.log is that the update state function is running immediately, rather than when the button is pressed - so it is going directly to the second "page" of the form.
Form Component
import React, {useState} from 'react';
import { View, Text} from 'react-native';
import Happiness from './Happiness';
const StarterForm = () => {
const [formStage, setFormStage] = useState(1)
const [happinessLevel, setHappinessLevel] = useState('')
console.log(formStage)
console.log(happinessLevel)
const increaseTheStage = (happiness) => {
setHappinessLevel(happiness)
setFormStage(formStage +1)
}
switch (formStage) {
case 1:
return (
<Happiness
passHappiness={increaseTheStage}
/>
)
case 2:
return (
<Text>This is the case of two</Text>
)
}
}
export default StarterForm;
Happiness component
import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
const Happiness = (props) => {
return (
<View>
<Text>Which of the following best classifies your happiness?</Text>
<TouchableOpacity onPress={props.passHappiness('Excellent')}>
<Text>Excellent</Text>
</TouchableOpacity>
</View>
)
}
export default Happiness;
Expected Results
I expect the following when the first screen opens:
console.log(formStage) = "1"
console.log(happinessLevel) = ""
Using anonymous functions
You are calling the function right away, switch it to this:
<TouchableOpacity onPress={() => props.passHappiness('Excellent')}>
Now you have created an anonymous function which calls passHappiness with the parameter 'Excellent' illustrated below:
() => props.passHappiness('Excellent')
Using bind
You can also use the bind method to "bind" the parameter "excellent" to the function
<TouchableOpacity onPress={props.passHappiness.bind(this,'Excellent')}>
More on the bind method here.

react native component button not enabling

import React from 'react';
import {
View,
Text,
Button,
TextInput,
StyleSheet
} from 'react-native';
const username = null;
const SetupForm = ({onSubmit}) => {
this.handleUsernameInput = (text) => {
username = text;
}
this.handleSetupSubmit = (event) => {
onSubmit(event, username);
}
this.handleSkipSubmit = (event) => {
onSubmit(event, false);
}
return (
<View>
<Text>Enter username:</Text>
<TextInput
placeholder="Username"
maxLength={20}
onSubmitEditing={this.handleSetupSubmit}
onChangeText={this.handleUsernameInput}
style={{ marginLeft: 20, marginRight: 20 }}
/>
<View>
<Button
title="Select"
onPress={this.handleSetupSubmit}
color="#34A853"
disabled={username === null}
/>
<Button
title="Maybe Later"
onPress={this.handleSkipSubmit}
color="red"
/>
</View>
</View>
);
}
export default SetupForm;
I have an issue with this Setup Form. it features a username text box I am setting to the value the user enters. onChangeText={this.handleUsernameInput}
for the select button I have set disabled when username === null however this never becomes false when entering text into the text box.
the text box is set to set the username when typing and I can see in the console its working correctly when I press the submit via the keyboard button with the redux action
{type: "SETUP.REQUEST", username: "aaaaaaa"}
is there something I am doing wrong here that the button is not becoming enabled when the text is getting set by the this.handleUsernameInput method?
example gif:
http://i.imgur.com/OuMkxHA.gifv
I have to click the skip button after typing in a username to make the button enable (go green), I want this to enable whilst typing
Like mentioned in the Garrett's comment the component doesn't re-render because there's no prop or state change when you change the text input. You should change the functional component to a ES6 class and save the username into the state. There's an simple example of this in the TextInput's documention
I'm not sure about your skill level but React's documentation about state and lifecycle is a good read if you are new to React https://facebook.github.io/react/docs/state-and-lifecycle.html

setState() adds a Proxy object to property instead of string value in react native

This is a very weird problem and I'm sure I'm overlooking something very simple.
When I load a new component AddNewCategory, I initially set a an empty string to a text property on this.state. Logging on console shows the text value as empty too.
I update this value using onChange of Button component. I know that the text property is so far updating as expected because the value of the input field changes accordingly.
<Button onChange={text=>this.setState({})}>
But when I try to retrieve the value of text property, I see that instead of a string, the text is now assigned a Proxy object.
I'm only trying to get the value of the input field so I can pass the value on to an action creator.
Here's the entire code,
import React from 'react';
import { View, Text, TextInput, Button} from 'react-native';
class AddNewCategory extends React.Component {
constructor(props) {
super(props)
this.state={
text: ''
};
console.log('after initialising constructor');
console.log(this.state);
this.onContinueButtonPress = this.onContinueButtonPress.bind(this);
}
onContinueButtonPress() {
console.log('after onContinueButtonPress');
console.log(this.state);
this.props.addNewCategory('Random Value');
}
render(){
return(
<View>
<Text>Name your new task list</Text>
<TextInput
placeholder="Things to do today.."
value={this.state.text}
onChange={(text)=>this.setState({text: text})}
/>
<Button
title={'Continue'}
onPress={this.onContinueButtonPress}
/>
</View>
);
}
};
export default AddNewCategory;
I have no idea why you are giving an onChange prop to a Button component.
Anyway, for a TextInput, you should give the onChangeText property.
<TextInput onChangeText={text => this.setState({ text })}
Other properties have been omitted.
Using just onChange is like handling the usual onChange event when doing web development, where the first parameter to the callback method only gives the event; to get the actual input value you have to say event.target.value.
onChange={(event) => console.log(event.target.value)}