react native component button not enabling - react-native

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

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.

Is it possible to wait for a component to render? React Testing Library/Jest

I have a component. It has a button. Upon pressing the button, I am changing the style of the button text (color) using setState function. When I am testing the changed component, the test is failing because the change happens asynchronously. I want to do something as is given here (https://testing-library.com/docs/dom-testing-library/api-async/)
const button = screen.getByRole('button', { name: 'Click Me' })
fireEvent.click(button)
await screen.findByText('Clicked once')
fireEvent.click(button)
await screen.findByText('Clicked twice')
But rather than waiting for the text to change. I want to wait for the text color to change. Thanks
This is the code for my button
<Button onPress = {() => {this.setState({state : 1});}}>
<Text style = {style}>Button Text</Text>
</Button>
So when this button is pressed. state is set to 1. And in render :
if(this.state.state === 1) style = style1
else style = style2;
But it can be seen from logs that render is called after the test checks for the styles. So How can I wait for the render to complete before checking if the font color has been changed?
Here is the testing code
test('The button text style changes after press', () => {
const {getByText} = render(<Component/>);
fireEvent.press(getByText('button'));
expect(getByText('button')).toHaveStyle({
color : '#ffffff'
});
})
It looks like you have a custom button, not a native button. I'm guessing your component is something like this:
import React from "react";
import {Text, TouchableOpacity} from "react-native";
const Button = ({pressHandler, children}) => (
<TouchableOpacity onPress={pressHandler}>
{children}
</TouchableOpacity>
);
const ColorChangingButton = ({text}) => {
const [color, setColor] = React.useState("red");
const toggleColor = () => setTimeout(() =>
setColor(color === "green" ? "red" : "green"), 1000
);
return (
<Button pressHandler={toggleColor}>
<Text style={{color}}>{text}</Text>
</Button>
);
};
export default ColorChangingButton;
If so, you can test it with waitFor as described here:
import React from "react";
import {
fireEvent,
render,
waitFor,
} from "#testing-library/react-native";
import ColorChangingButton from "../src/components/ColorChangingButton";
it("should change the button's text color", async () => {
const text = "foobar";
const {getByText} = render(<ColorChangingButton text={text} />);
fireEvent.press(getByText(text));
await waitFor(() => {
expect(getByText(text)).toHaveStyle({color: "green"});
});
});
For a native button which has rigid semantics for changing colors and doesn't accept children, instead using title="foo", a call to debug() shows that it expands to a few nested elements. You can use
const text = within(getByRole("button")).getByText(/./);
expect(text).toHaveStyle({color: "green"});
inside the waitFor callback to dip into the button's text child and wait for it to have the desired color.
I used the same packages/versions for this post as shown in React Testing Library: Test if Elements have been mapped/rendered.
You can try
<Text style = {this.state.state === 1 ? style1 : style2}>Button Text</Text>
This will consequently lead to the style being defined all time. So you don't have to wait for the setState to complete.
Edit
You can use the callback provided by setState function to perform your tests for styles.
this.setState({
state : 1
} , () => {
//this is called only after the state is changed
//perform your test here
})

React native button need twice click to change state

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.

I am unable to save the details when clicked Add button in EventForm page must display in EventList page in react native

Unable to display the text entered in the Eventform and show it on the flatlist of EventList page.I am new to react native just need some help to solve the problem. Learning to develop a notes application.
EventForm js I am entering the text in it which has name location and notes field but when press add button does not showing it in the flatlist.
class EventForm extends Component {
state = {
title: null,
date: '',
};
handleAddPress = () => {
saveevents(this.state)
// console.log('saving events:', this.state);
.then(()=> this.props.navigation.goBack());
}
// handlePress() {
// this.props.onBtnPress()
// }
// }
handleChangeTitle = (text) => {
this.setState({ title: text });
}
handleChangeLocation =(text) => {
this.setState({location: text});
}
render() {
return (
<View
style={{
flex: 1
}}
>
<View style={styles.fieldContainer}>
<TextInput
style={styles.text}
placeholder="Name"
spellCheck={false}
value={this.state.title}
onChangeText={this.handleChangeTitle}
/>
<TextInput
style={styles.text}
placeholder="Enter your Location"
spellCheck={false}
value={this.state.location}
onChangeText={this.handleChangeLocation}
/>
<AutoExpandingTextInput
placeholder="Write your Notes here"
spellCheck={false}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
</View>
<TouchableHighlight
onPress ={() =>this.handleAddPress.bind(this)}
// onPress={this.handleAddPress}
style={styles.button}
>
<Text style={styles.buttonText}>Add</Text>
</TouchableHighlight>
</View>
EventList js where I would like to display the dynamic text entered in EventForm should appear in flatlist. I am saving the flatlist content in db json file and calling it in the EventList.
const styles = StyleSheet.create({
list: {
flex: 1,
paddingTop: 20,
backgroundColor: '#A9A9A9'
},
});
class EventList extends Component {
state = {
events: [],
}
componentDidMount() {
//getEvents().then(events => this.setState({ events }));
const events = require('./db.json').events;
this.setState({ events });
}
render() {
return [
<FlatList
key="flatlist"
style={styles.list}
data={this.state.events}
renderItem={({ item, seperators }) => (<EventCard events=
{item} />)}
keyExtractor={(item, index) => index.toString()}
/>,
My db json file is this which I have manually entered the details.Data that is dynamically entered have to save in db json file and should reflect in the flatlist.
{
"events":[
{
"name":"chandu",
"date":"15-06-2018 ",
"location":"Sydney",
"content":"How are you..?",
"id":"05dafc66-bd91-43a0-a752-4dc40f039144"
},
{
"name":"bread",
"date":"15-07-2018 ",
"location":"Sydney",
"content":"I bought bread..?",
"id":"05dafc66-bd91-43a0-a752-4dc40f039145"
}
]
}
I am expecting whatever the text that is entered in the form should save and show me on the Flatlist which is in EventList file. Please help if you get any solution for it.
I have added alert message when onPressed to show that whether it is pressed or not.
I am expecting whatever the text that is entered in the form should save and show me on the Flatlist which is in EventList file. Please help if you get any solution for it.
I have added alert message when onPressed to show that whether it is pressed or not.
Your EventForm and EventList are two separate component without any shared props.
Assuming you are updating db.json file (using file read/write methods) from EventsForm component, still in the EventsList the data is fetched only once on componentDidMount.
You will need to pass the data for EventList as props or keep in state. If you keep it in props, then you must update the value of state using some life cycle method such as getDerivedStateFromProps props or something similar.
Edit:
I would suggest using global state management library like redux, for saving your data entered in the EventForm component, instead of read/write in a file.
You can save the data by dispatching an action in your EventForm component.
Later access that data in you EventList component using
this.props.your_db_name
You can save this data even on app kill using redux-persist
If you still want to continue with file read/write, you can look at this library react-native-fs

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)}