Problem with React-Native Output View Component - reactjs

this code does not Display the list(places) which places i added to it using add_Button.
Generally working of this code is this that i input text into this react-native app using TextInput Component, after this i press the Add Button to add this text into a list(places), after this it automatically display all the entered text.
e.g if i enter the place by 1st time it only display that text, but if i enter another text it displays that text as well as the first one.
import React, {Component} from 'react';
import {View, TextInput, StyleSheet, Button, Text} from 'react-native';
export default class App extends Component
{
state = {
placeName: "",
places: []
};
placeNameChangeHandler=(val)=>
{
this.setState({
InputValue: val
})
};
placeSubmitHandler = () =>{
if(this.state.placeName.trim() === "")
{
return;
}
this.setState(prevState => {
return {
places : prevState.places.concat(prevState.placeName)
};
});
};
render()
{
const placesOutput = this.state.places.map((place, i) =>(
<Text key={i} backgroundColor = 'black' >{place}</Text>
));
return(
<View style={Styles.container}>
<View style = {Styles.inputContainer}>
<TextInput
placeholder = "Search place?"
value = {this.setState.placeName}
onChangeText = {this.placeNameChangeHandler}
style={Styles.placeInput}
/>
<Button
title='Add'
style = {Styles.placeButton}
onPress = {this.placeSubmitHandler}
/>
</View>
<View>{placesOutput}</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
flex:1,
padding: 10,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-start'
},
inputContainer: {
width: "100%",
flexDirection : 'row',
justifyContent: 'space-between',
alignItems:'center'
},
placeInput: {
width: "70%"
},
placeButton: {
width: "30%"
}
})

This is not 100% correct, but I'll write it down.
This seems to happen because of setState.
First.
Change to value = {this.setState.placeName} to value = {this.state.placeName}
<TextInput
placeholder = "Search place?"
value = {this.state.placeName}
onChangeText = {this.placeNameChangeHandler}
style={Styles.placeInput}
/>
Next.
Change setState in placeNameChangeHandler
placeNameChangeHandler=(val)=>{
this.setState({
placeName: val
})
};
And
Add Initializing placeName
placeSubmitHandler=()=>{
if(this.state.placeName.trim() === "")
{
return;
}
this.setState(prevState => {
return {
places : prevState.places.concat(prevState.placeName),
placeName : ""
};
});
};
Sorry for my stupid English.
I hope you understand :)

Related

React Native Text Input "Each child in a list should have a unique "key" prop."

When I run this code in my Expo project, i get the following error:
Warning: Each child in a list should have a unique "key" prop.
Check the render method of AddParticipant.
Can someone hep me here please ?
import React, { Component } from 'react';
import { View, TextInput, Button, StyleSheet } from 'react-native';
class AddParticipant extends Component {
constructor(props){
super(props);
this.state = {
textInput : [],
inputData : []
}
}
//function to add TextInput dynamically
addTextInput = (index) => {
var name_id = " First Name & Last Name" + " " +(index +1 );
let textInput = this.state.textInput;
textInput.push(<TextInput style={styles.textInput} placeholder={name_id}
onChangeText={(text) => this.addValues(text, index)} />
);
this.setState({ textInput });
}
//function to remove TextInput dynamically
removeTextInput = () => {
let textInput = this.state.textInput;
let inputData = this.state.inputData;
textInput.pop();
inputData.pop();
this.setState({ textInput,inputData });
}
//function to add text from TextInputs into single array
addValues = (text, index) => {
let dataArray = this.state.inputData;
let checkBool = false;
if (dataArray.length !== 0){
dataArray.forEach(element => {
if (element.index === index ){
element.text = text;
checkBool = true;
}
});
}
if (checkBool){
this.setState({
inputData: dataArray
});
}
else {
dataArray.push({'text':text,'index':index});
this.setState({
inputData: dataArray
});
}
}
//function to console the output
getValues = () => {
console.log('Data',this.state.inputData);
}
render(){
return(
<View>
<View style= {styles.row}>
<View style={{margin: 10}}>
<Button title='Add Participant' onPress={() => this.addTextInput(this.state.textInput.length)} />
</View>
<View style={{margin: 10}}>
<Button title='Remove Participant' onPress={() => this.removeTextInput()} />
</View>
</View>
{this.state.textInput.map((value) => {
return value
})}
<Button title='Save The Participants' onPress={() => this.getValues()} />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
buttonView: {
flexDirection: 'row'
},
textInput: {
height: 40,
borderColor: 'black',
borderWidth: 1,
margin: 20
},
row:{
flexDirection: 'row',
justifyContent: 'center'
},
});
export default AddParticipant;
The that you're returning must have some key associated. i.e. you must provide a key for every component.
Here's what you can do,
addTextInput = (index) => {
var name_id = " First Name & Last Name" + " " +(index +1 );
var key = index; // add this statement in the code. It'll remove the warning
let textInput = this.state.textInput;
textInput.push(<TextInput key={key} style={styles.textInput} placeholder={name_id}
onChangeText={(text) => this.addValues(text, index)} />
);
this.setState({ textInput });
}

How can I read the value inside a TextInput?

I have a TextInput, and have a function named onEnterPin.
But i just couldnt reach that value. All I want is to get the value inside TextInput, and navigate to another screen if the value inside TextInput is correct
Could you help me? Btw one more question: After the pin is correct, i navigate to Home screen, and on Home screen I should have rooms(like living room etc, and items(tv, internet etc) under the room name and picture. Could you give me hint?
Here is the code
import React, { useState } from "react";
import { Text, View, Button, StyleSheet, TextInput, Alert } from "react-native";
const SplashScreen = ({ navigation }) => {
const [pin, setPin] = useState('');
const CORRECT_PIN = "5555";
const onEnterPin = (pin)=>{
if(pin === CORRECT_PIN) {
navigation.navigate("Home");
}
else{
Alert.alert("problem here")
}
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Welcome to Rooms Page</Text>
<Button
title="Go to HomeScreen"
onPress = {() => {
navigation.navigate("Home", {
itemId: 86,
otherParam: "anything you want here"
});
}} // go to the screen named Home
/>
<Text>PIN gir</Text>
<TextInput value={pin} style={styles.textInput} onChangeText={pin => setPin(pin)}></TextInput>
<Button
title="Enter"
onPress = {() => {
onEnterPin(value); // i guess the problem is here, what should i write
}}
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#307ecc',
},
textInput: {
borderWidth:.5,
height:35,
margin:12,
}
});
export default SplashScreen;
HomeScreen.js
import React from "react";
import { View, Text, Button } from "react-native";
const HomeScreen = ({ route, navigation }) => {
const { itemId } = route.params;
const { otherParam } = route.params;
return(
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
title="Go back"
onPress = {() => navigation.goBack()}
/>
<Button
title="go to example screen"
onPress={() => navigation.navigate("Example")}
/>
<Button
title="go to Home page again, using push"
onPress = {() => {
navigation.push("Home", {
itemId: Math.floor(Math.random() * 100)
}),
navigation.setParams({itemId:200}) // it updates itemId as 200, then does random number job in Math.random()
}}
/>
</View>
// Avoid using setParams to update screen options such as title etc. If you need to update options, use setOptions instead.
)
}
export default HomeScreen;
Change onEnterPin parameter from value to pin like this:
<Button
title="Enter"
onPress = {() => {
onEnterPin(pin); // <<<<<<<<<<<<<<<<
}}
/>
my Textinput has an ID and with this we can do this:
document.getElementById(id).value
to get the value of the Input.
You don't need to pass it to a function since the pin value already exists in local state:
const onEnterPin = () => {
if (pin === CORRECT_PIN) {
navigation.navigate("Home");
}
else {
Alert.alert("problem here")
}
};
and:
<TextInput value={pin} style={styles.textInput} onChangeText={setPin} />
<Button
title="Enter"
onPress={onEnterPin}
/>
As the 'pin' variable exists as a local state, you can use it in the 'onEnterPin()' method, without using a parameter.
The 'onEnterPin' method will be as:
const onEnterPin = () => {
if(pin === CORRECT_PIN) {
navigation.navigate("Home")
}
else{
Alert.alert("problem here")
}
}

displaying input field after clicking button react-native

I am learning react-native and I wanted to do something simple where the user can enter some information like name or something and then when he/she clicks the button, it will display on the screen hello so and so. I have my onChangeText setting the state to what the user passes but it doesn't update. Also clicking the button doesn't show anything. I will paste my code down below. Any help or suggestions.
app.js
import { Button } from "react-native";
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View,
Alert,
TextInput
} from "react-native";
const instructions = Platform.select({
ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",
android:
"Double tap R on your keyboard to reload,\n" +
"Shake or press menu button for dev menu"
});
type Props = {};
export default class App extends Component<Props> {
constructor() {
super();
this.state = {
text: "Hello "
};
this.handleChange = this.handleChange.bind(this);
}
handleChange = typedText => {
this.setState({
text: typedText
});
console.log(text);
};
render() {
return (
<View style={styles.container}>
<Text>{this.state.value}</Text>
<Button onPress={this.handleChange} title="Click Me " />
<TextInput
placeholder="Type your name here"
onChangeText={typedText => {
this.setState({
text: typedText
});
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5
}
});
You are setting the state in handlechange (the onpress function) as well which is not required at all. There wont be an argument of text in your onPress you are resetting the text value in the state. And the text inside the handleChange will be undefined as you dont set it anywhere.
the code should be something like below.
export default class App extends Component {
constructor() {
super();
this.state = {
text: "Hello "
};
this.handleChange = this.handleChange.bind(this);
}
onPress = () => {
console.log("current ==> ", this.state);
alert(this.state.text);
};
handleChange = typedText => {
console.log("update => ", typedText);
this.setState(
{
text: typedText
}
);
};
render() {
return (
<View style={styles.container}>
<Text>{this.state.value}</Text>
<Button onPress={this.onPress} title="Click Me " />
<TextInput
placeholder="Type your name here"
onChangeText={this.handleChange}
/>
</View>
);
}
}
The issue was, on Press of button we are calling a function which expects a 'text' but in actual it is an event.
Check this codesandbox

How can I change the color of an icon without re-render (TextField loosing focus)

I am using the package called react-native-phone-input, and when the phone number is changed it runs the function this.updateInfo() which updates the state. In my code, the icon color is dependent on the state and changes based on whether the phone number is valid. This works, however, when the state is changed, the screen re-renders and the keyboard is dismissed since the text field loses focus. Is there another way I can change the icons color? Or is there a way that I can keep the focus on the text field?
This is what I am referring to:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, TextInput, Keyboard} from 'react-native';
import { Icon } from 'react-native-elements';
import KeyboardAccessory from 'react-native-sticky-keyboard-accessory';
import PhoneInput from 'react-native-phone-input';
export default class PhoneLogin extends Component {
constructor() {
super();
this.state = {
valid: "",
type: "",
value: "",
iconColor: "#D3D3D3",
};
this.updateInfo = this.updateInfo.bind(this);
}
updateInfo() {
this.setState({
valid: this.phone.isValidNumber(),
type: this.phone.getNumberType(),
value: this.phone.getValue().replace(/[- )(]/g,''),
});
}
render() {
return (
<View style={styles.container}>
<PhoneInput
ref={ref => {
this.phone = ref;
}}
style={{height: 50, borderColor:'#44c0b9', borderBottomWidth:2}}
onChangePhoneNumber={ (phone) => {this.updateInfo()} }
/>
<KeyboardAccessory backgroundColor="#fff">
<View style={{ alignItems: 'flex-end', padding:10 }}>
<Icon
raised
reverse
color={(this.state.valid) ? "#44c0b9" : "#D3D3D3"}
name='arrow-right'
type='font-awesome'
onPress={ Keyboard.dismiss()}
/>
</View>
</KeyboardAccessory>
</View>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
padding: 20,
paddingTop: 60
},
info: {
// width: 200,
borderRadius: 5,
backgroundColor: "#f0f0f0",
padding: 10,
marginTop: 20
},
button: {
marginTop: 20,
padding: 10
}
});
In your onPress of your Icon you need to send an arrow function.
The Icon should be like this
<Icon
raised
reverse
color={(this.state.valid) ? "#44c0b9" : "#D3D3D3"
name='arrow-right'
type='font-awesome'
onPress={() => Keyboard.dismiss()}
/>
The problem was the Keyboard.dismiss() was immediately running every time the component re-rendered thus dismissing your keyboard.
Hope this helps!

React native how to animate view opening up->down

Consider the following component where the user selects an option from a list:
import React, { Component } from "react";
import PropTypes from "prop-types";
import {
View,
Text,
StyleSheet,
Platform,
FlatList,
TouchableNativeFeedback,
TouchableOpacity,
PLatform
} from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
import { colors, metrics } from "../../themes";
const Touchable =
Platform.OS === "android" ? TouchableNativeFeedback : TouchableOpacity;
class MenuSelector extends Component<{
onSelect: () => any,
config: object,
selected: string
}> {
state = {
listOpened: false
};
handlePress = id => {
this.props.onPress(id);
};
handleSelect = id => {
if (this.props.onSelect) this.props.onSelect(id);
this.setState({
listOpened: false
});
};
handleMenu = () => {
this.setState({
listOpened: !this.state.listOpened
});
};
render = () => {
let title = "";
if (this.props.config) {
title = this.props.config[0].title;
if (this.props.selected) {
let found = this.props.config.find(item => {
return item.id === this.props.selected;
});
if (found) title = found.title;
}
}
let top = (
<View style={styles.header}>
<Text style={styles.text}>{title}</Text>
<Touchable>
<Text style={styles.text}>
<Icon
name={"ios-menu"}
size={20}
onPress={this.handleMenu}
/>
</Text>
</Touchable>
</View>
);
let list = null;
if (this.state.listOpened === true) {
list = (
<FlatList
data={this.props.config}
renderItem={({ item }) => (
<Touchable onPress={this.handleSelect}>
<Text style={[styles.text, styles.listItem]}>{item.title}</Text>
</Touchable>
)}
/>
);
}
return (
<View style={styles.container}>
{top}
{list}
</View>
);
};
}
export default MenuSelector;
const styles = StyleSheet.create({
container: {
flex: -1,
flexDirection: "column"
},
header: {
flex: -1,
flexDirection: "row",
justifyContent: "space-between",
padding: 10,
backgroundColor: "blue"
},
text: {
fontSize: 16,
color: "white",
textAlign: "center",
fontWeight: "bold"
},
listItem: {
padding: 10,
backgroundColor: "blue"
}
});
The component is used in the following context:
let config = [
{
title="Option 1",
id="option1"
},
{
title="Option 2",
id="option2"
},
{
title="Option 3",
id="option3"
},
{
title="Option 4",
id="option4"
},
];
return (
<View style={styles.container}>
<MenuSelector
config={config.options}
selected={this.state.mode}
onPress={this.handleButtonListPress}
/>
<FlatList
data={this.props.data}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<Text style={styles.text}>{item.name}</Text>
)}
/>
</View>
);
As it is, the <MenuSelector> component appears "at once" on screen. I need to add an sliding effect to <MenuSelector>, "pushing down" the data FlatList when appearing on screen...
On closing, same behaviour, but animating from down to up.
How can I add such animation behaviour to my MenuSelector component ?

Resources