React-Native: Expo stops when I add Picker item - javascript

I'm new to react-native, I'm trying to use Picker item to selct from a dropdown, I'm using react hooks to set Picker items to be selectable, however Expo stops without warning when I add the code:
const HomeScreen3 = observer(() =>
{
const [ options, setOptions ] = useState([ { id:1, title:'Titulo 1' }, { id:2, title:'Titulo 2' } ]);
const [ selectedOption, setSelectedOption ] = useState({ id:1, title:'Titulo 1' });
useEffect(() => {
console.log('component mounted');
}, []);
return (
<View style={{flex: 1, backgroundColor: '#fff', padding:10, position:'relative' }}>
<ScrollView showsHorizontalScrollIndicator={false}>
<Picker
itemStyle={{ backgroundColor: "white", color: "black", borderColor:'rgba(0,0,0,0.2)', fontSize:16, }}
mode="dropdown"
selectedValue={selectedOption}
onValueChange={(value) => { setSelectedOption( value)}}>
{options.map((item, index) => {
return (<Picker.Item label={item} value={item} key={index}/>)
})}
</Picker>
</ScrollView>
</View>
export default HomeScreen3;

for expo use this works for me even is there a warn but works!
import { Picker } from 'react-native'
// state
const [picked, setPicked] = useState(1.15);
<Picker
selectedValue={picked}
style={{ height: 50, width: 100 }}
onValueChange={(itemValue, itemIndex) =>
setPicked(itemValue)
}>
<Picker.Item label="Canda 5%" value={1.05} />
<Picker.Item label="Japan 8%" value={1.08} />
<Picker.Item label="USA 10%" value={1.10} />
<Picker.Item label="Egypt 14%" value={1.14} />
<Picker.Item label="Saudi Arabia 15%" value={1.15} />
<Picker.Item label="China 16%" value={1.16} />
<Picker.Item label="Algeria 17%" value={1.17} />
<Picker.Item label="18%" value={1.18} />
<Picker.Item label="German 19%" value={1.19} />
<Picker.Item label="German 19%" value={1.20} />
</Picker>

First of all, in Expo SDK 38 the import { Picker } from 'react-native'; is no longer working as expected.
Make sure you use import { Picker } from '#react-native-community/picker';
Here is the documentation for it: https://github.com/react-native-community/react-native-picker.
Second, the real problem I see is an issue with your code is that for the Picker.Item, here:
{options.map((item, index) => {
return (<Picker.Item label={item} value={item} key={index}/>)
})}
you are sending the complete objects in the label and item props. However, looking at the actual documentation, label accepts a string and value accepts string or integer - https://reactnative.dev/docs/picker-item
That means your Picker code should look like this:
<Picker
itemStyle={{backgroundColor: "white", color: "black", borderColor:'rgba(0,0,0,0.2)', fontSize:16}}
mode="dropdown"
selectedValue={selectedOption}
onValueChange={(value) => {setSelectedOption(value)}}>
{options.map((item, index) => {
return (<Picker.Item label={item.id} value={item.title} key={index}/>)
})}
</Picker>
and the selectedOption should only store the id of the item like this:
const [ selectedOption, setSelectedOption ] = useState(1);

Related

react native : value of the picker does not change

The value of the picker does not change if I select another value from it
It just happened when I added onValueChange
I would be happy to help with this
const [eventType, setEventType] = useState<any>();
<Picker
onValueChange={(itemValue, itemIndex) => { setEventType(itemValue) }}
dropdownIconColor='black'
mode="dropdown">
{stateList.map(option => <Picker.Item label={option.label} key={option.key} value={option.value} />)}
</Picker>
Can you please try this. I think you should add your code selectedValue
<Picker
onValueChange={(itemValue, itemIndex) => { setEventType(itemValue) }}
selectedValue={eventType}
dropdownIconColor='black'
mode="dropdown">
{stateList.map(option => <Picker.Item label={option.label} key={option.key} value={option.value} />)}
</Picker>

React Native: What is the way to make the second picker (selectedValue2) works?

What is the way to make the second picker (selectedValue2) works ?
When i try to change the second picker so its not change its value and i don't understand why .
I would love to know what the reason is and how I handle it .
import React, { useState } from 'react';
import { Platform, ScrollView, StyleSheet, Text, View } from 'react-native';
import { Picker } from '#react-native-community/picker';
const Settings = () => {
const [selectedValue, setSelectedValue] = useState('java');
const [selectedValue2, setSelectedValue2] = useState('ddd');
return (
<>
<View style={{ marginTop: 20 }}>
<Text style={styles.text}>choose</Text>
</View>
<View style={styles.container}>
<Picker
selectedValue={selectedValue}
style={{
height: 50,
width: 150,
justifyContent: 'flex-end',
// marginRight: 100,
}}
onValueChange={(itemValue, itemIndex) => setSelectedValue(itemValue)}
>
<Picker.Item label="Java" value="java" />
<Picker.Item label="JavaScript" value="js" />
</Picker>
<Picker
selectedValue2={selectedValue2}
style={{
height: 50,
width: 150,
justifyContent: 'flex-end',
// marginRight: 100,
}}
onValueChange={(itemValue, itemIndex) => setSelectedValue2(itemValue)}
>
<Picker.Item label="sss" value="ss" />
<Picker.Item label="zzz" value="zz" />
</Picker>
</View>
</>
);
};
The problem in the second picker is that there is no such property selectedValue2 on the Picker component. That is the name of your local state variable, but the property of the component is selectedValue. This means your changes aren't propagated to the component. Here is the correct way:
<Picker
selectedValue={selectedValue2}
...

React Native FlatList only gets updated when TextInput or Picker changes

I'm trying to dynamically add text from an input field and a picker to a FlatList in React Native. The problem I have is that the FlatList doesn't get updated as soon as I hit the button.
The item does get added to the list eventually but only after I trigger the onChangeText of the text input or the onValueChange of the picker element.
import React, { Component } from 'react';
import { View, Text, Picker } from 'react-native';
import { TextInput } from 'react-native-paper';
import { TouchableOpacity, FlatList, ScrollView } from 'react-native-gesture-handler';
CreateSetScreen = () => {
const [value, onChangeText] = React.useState('Placeholder');
const [pickerValue, setPickerValue] = React.useState("1");
const [listValues, setListValue] = React.useState([]);
joinData = () => {
listValues.push({"content": value, "category": pickerValue, "key": listValues.length.toString()});
setListValue(listValues);
}
return(
<View>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={text => onChangeText(text)}
value={value}
/>
<Picker
selectedValue={pickerValue}
style={{height: 50}}
onValueChange={(itemValue) => setPickerValue(itemValue)}
>
<Picker.Item label="Kategorie 1 - 1%" value="1" />
<Picker.Item label="Kategorie 2 - 10%" value="2" />
<Picker.Item label="Kategorie 3 - 20%" value="3" />
<Picker.Item label="Kategorie 4 - 29%" value="4" />
<Picker.Item label="Kategorie 5 - 40%" value="5" />
</Picker>
<TouchableOpacity
style={{backgroundColor:'#DDDDDD'}}
onPress={() => joinData()}
>
<Text>Add Item!</Text>
</TouchableOpacity>
<FlatList
data={listValues}
renderItem={({item}) => (<Text>{item.category}: {item.content}</Text>)}
/>
</View>
)
}
export default CreateSetScreen;
Any help is appreciated, thank you.
It seems .push() works in the setter function from React Hooks but It doesn't. Rather than returning the array itself, .push() returns the length of the array after modification.
On the other hand, .concat() works to update state, that is .concat() creates a new array and then returns the changed array.
So just change your joinData function a little bit in this way.
const joinData = () => {
setListValue(listValues => listValues.concat({ "content": value, "category": pickerValue, "key": listValues.length.toString() }));
}
Try adding a key extractor to your FlatList:
<FlatList
data={listValues}
renderItem={({item}) => (<Text>{item.category}: {item.content}</Text>)}
keyExtractor={(item, index) => String(index)}
/>

React Native Dynamically created components not rendering on first click

I'm trying to create a list by dynamically adding the list items to an array in the state and then using the map operator to iterate over them. However, the new list items are only rendered after the second click on the button that handles the setState method. Any pointers on resolving this?
...
constructor(props) {
super(props);
this.state = {
requirements:[], // Placeholder array in state
currentRequirement
}
}
...
And in my render method I have this.
{
this.state.requirements.map((el,i) => (
<TouchableOpacity key={i}>
<BulletItem text={el}/>
</TouchableOpacity>
))
}
<FormInput
onChangeText={(value) => {
this.setState({ currentRequirement: value})}
}
placeholder="Enter a new requirement"
/>
<Button
title="Add Requirement"
onPress={() => {
this.onAddRequirementComponent()
}}
/>
The method for handling the setState is this.
onAddRequirementComponent() {
this.setState(previousState => ({
requirements: [...previousState.requirements, this.state.currentRequirement],
currentRequirement:''
}))
}
UPDATE : FULL COMPONENT
import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView, Picker, TouchableOpacity } from 'react-native';
import { BulletItem, TagCloud } from "../components/index";
import { Actions } from "react-native-router-flux";
import {
Button,
Header,
FormInput,
FormLabel,
} from 'react-native-elements';
export default class ListScreen extends Component {
constructor(props) {
super(props);
this.state = {
jobtype: '',
level: '',
requirements: [],
benefits: [],
currentRequirement: '',
currentBenefit: ''
}
}
render() {
return (
<View style={styles.container}>
<Header
backgroundColor='#fff'
borderBottomWidth={0}
leftComponent={{ icon: 'corner-up-left', color: '#333', type: 'feather', onPress: () => { Actions.pop() } }}
centerComponent={{ text: 'Create New Job', fontFamily: 'VarelaRound-Regular', style: { color: '#333', fontSize: 18 } }}
rightComponent={{ icon: 'options', color: '#333', type: 'simple-line-icon' }} />
<ScrollView>
<FormLabel>Job Title</FormLabel>
<FormInput placeholder="e.g. Full Stack Javascript Developer"/>
<FormLabel >REQUIREMENTS</FormLabel>
{
this.state.requirements.map((el, i) => (
<TouchableOpacity key={i}><BulletItem containerStyle={{ backgroundColor: '#EFF0F2', borderRadius: 4 }} style={{ backgroundColor: '#EFF0F2' }} text={el} /></TouchableOpacity>
))
}
<FormInput
onChangeText={(value) => {
this.setState({ currentRequirement: value})}
}
placeholder="Enter a new requirement"
/>
<Button
title="Add Requirement"
onPress={() => {
this.onAddRequirementComponent()
}}
/>
<FormLabel style={{ fontFamily: 'VarelaRound-Regular', color: '#333' }} labelStyle={{ fontFamily: 'VarelaRound-Regular', color: '#333' }}>BENEFITS</FormLabel>
{
this.state.benefits.map((el, i) => (
<TouchableOpacity key={i}><BulletItem text={el} /></TouchableOpacity>
))
}
<FormInput value={this.state.currentBenefit} onChangeText={(value) => { this.setState({ currentBenefit: value }) }} placeholder="3 years experience developing Javascript apps" />
<Button title="Add" onPress={() => { this.onAddBenefitComponent() }}/>
<Picker selectedValue={this.state.jobtype}
style={{ height: 50, width: '100%', backgroundColor: '#EFF0F2' }}
onValueChange={(itemValue, itemIndex) => this.setState({ jobtype: itemValue })}>
<Picker.Item label="Full Time" value="fulltime" />
<Picker.Item label="Part Time" value="parttime" />
<Picker.Item label="Contract" value="contract" />
<Picker.Item label="Remote" value="remote" />
</Picker>
<Picker selectedValue={this.state.level}
style={{ height: 50, width: '100%', backgroundColor: '#EFF0F2' }}
onValueChange={(itemValue, itemIndex) => this.setState({ level: itemValue })}>
<Picker.Item label="Junior" value="junior" />
<Picker.Item label="Mid-Level" value="mid" />
<Picker.Item label="Management" value="management" />
<Picker.Item label="Senior" value="senior" />
</Picker>
</ScrollView>
</View>
);
}
onAddRequirementComponent() {
if (this.state.currentRequirement)
this.setState(previousState => ({
requirements: [...previousState.requirements, this.state.currentRequirement],
currentRequirement: ''
}))
}
onAddBenefitComponent() {
this.setState(previousState => ({
benefits: [...previousState.benefits, this.state.currentBenefit],
currentBenefit: ''
}))
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
}
});
This is the core logical part and works perfectly. I used only native elements like TextInput. The only change I made to make the TextInput to full controlled by adding value={this.state.currentRequirement} plus the suggestion of #Tholle for the usage of previousState.
class Test extends Component {
state = {
requirements: [],
currentRequirement: ''
}
onAddRequirementComponent() {
this.setState(previousState => ({
requirements: [...previousState.requirements, previousState.currentRequirement],
currentRequirement:''
}))
}
render() {
return(
<View>
<TextInput onChangeText={(value) => {
this.setState({ currentRequirement: value})}
}
value={this.state.currentRequirement}
/>
{ this.state.requirements.map((el,i) => (
<Text key={i}>{el}</Text>
))}
<Button
title="Add Requirement"
onPress={() => {
this.onAddRequirementComponent()
}}
/>
</View>
);
}
}

How to make react-native Picker stay at newly selected option?

I have a picker that I'm testing on iOS right now with two options. Every time I drag down from the first option to the second option, the picker immediately returns to the first option.
This is what my the code for my picker looks like.
<Picker
style={{
width: 100,
}}
selectedValue={(this.state && this.state.pickerValue) || 'a'}
onValueChange={(value) => {
this.setState({value});
}} itemStyle={{color: 'white'}}>
<Picker.Item label={'Hello'} value={'a'} />
<Picker.Item label={'World'} value={'b'} />
</Picker>
I want the selector to stay at the newly scrolled-to option. I've also removed the || 'a' part of the selectedValue attribute but that didn't solve the issue either.
On value change you need to specify which property of the state changed and change it accordingly with this.setState
onValueChange={(value) => {this.setState({pickerValue: value});
Complete Code
<Picker
style={{
width: 100,
}}
selectedValue={(this.state && this.state.pickerValue) || 'a'}
onValueChange={(value) => {
this.setState({pickerValue: value});
}} itemStyle={{color: 'white'}}>
<Picker.Item label={'Hello'} value={'a'} />
<Picker.Item label={'World'} value={'b'} />
</Picker>
I just came across this and was facing the same issue, the scrolling reaches the new item and resets to the first item.
I have done this using stateless component (Hooks):
I have an array of objects as the value and option as key
const data = useState({
"options":[{
"name":"Dish 1","price":0},{"name":"Dish 2","price":0}]})
const [selected, setSelected] = useState(0)
The Picker component:
<PickerIOS
selectedValue={selected_choice}
onValueChange={(value, index) => {
set_selected_choice(index)
}}
>
{data?.map((item, index) => (
<PickerIOS.Item
key={item}
value={index}
label={item.name}
/>
))}
</PickerIOS>
Here, I have stored the index of the array elements in the selected state and have updated it from the PickerIOS Item, keeping the value as index.
I used this "hack":
render() {
const values = ['1', '2'];
return (
<Picker
value={this.state.value}
onValueChange={this.onValueChange.bind(this)}
>
{
<Picker
value={this.state.value}
onValueChange={this.onValueChange.bind(this)}
>
{
[<Picker.Item
label="n/a"
value={null}
/>].concat(values.map(value => {
return (
<Picker.Item
label={value}
value={value}
/>
)
})
)
}
</Picker>
);
}

Categories

Resources