'Universal' function to handle 'onValueChange' for multiple 'picker' controls...possible? - react-native

The following code is written in React Native, and is completely functional. It displays a 'picker' for the user to select a value and then assigns the selected value to a 'state' variable for display in the interface:
import {Picker} from '#react-native-community/picker';
export default class Info extends Component {
constructor(props) {
super(props);
this.state = {
typeValues: [{"name": "Business Type", "id": 0}, {"name": "franchise", "id": 1}, {"name": "corporate", "id": 2}, {"name": "independent", "id": 3}],
typeItem: ''
};
}
typeChange = (index) => {
this.state.typeValues.map((v,i) => {
if (index === i ) {
this.setState({ typeItem: this.state.typeValues[index].name }) //setState
} //index EQUALS 'i'...
}) //map
}
...
render() {
return (
<>
<Text style={{ padding: 10, color: "#000000", textAlign: 'center', fontSize: 32, fontWeight: 'bold' }}>
{this.state.typeItem}
</Text>
<Picker
selectedValue={this.state.typeItem}
style={{width: deviceWidth, height: 40 }}
onValueChange={(itemValue, itemIndex) => this.typeChange(itemIndex)}>
{ this.state.typeValues.map( (v, key)=>{
return <Picker.Item label={v.name} value={v.id} key={key} />
}) }
</Picker>
</>
)
} //render
...
} //class Info
My issue is what should be done if I have many 'picker' controls. Presently the 'OnValueChange' handler ("typeChange") handles the 1 'picker' control I have. However if there are more, say 5 or 10 more 'picker' controls...I would have to write/copy an 'OnValueChange' handler for each. That is ugly and I am sure there must be a better way, perhaps a single function that could handle 'OnValueChange' from ANY 'picker' control.
For example if I added more arrays for additional 'picker' controls:
this.state = {
typeValues: [{"name": "Business Type", "id": 0}, {"name": "franchise", "id": 1}, {"name": "corporate", "id": 2}, {"name": "independent", "id": 3}],
smokingValues: [{"name": "Smoking Allowed", "id": 0}, {"name": "Yes", "id": 1}, {"name": "No", "id": 2}, {"name": "Unknown", "id": 3}],
takeoutValues: [{"name": "Takeout Available", "id": 0}, {"name": "Yes", "id": 1}, {"name": "No", "id": 2}, {"name": "Unknown", "id": 3}],
typeItem: '',
smokingItem: '',
takeoutItem: '',
etc...
};
Is there a way to handle the 'OnValueChange' function for each and every 'picker' that is created...within a single 'universal' function? It seems difficult to believe it would be necessary to write a function for each 'picker' to store the selected value into the appropriate 'state' variable. Any suggestions greatly appreciated. I thank you in advance.

Related

How to get the values of Selected Radio buttons from Radio Groups

Im using react-native-flexi-radio-button for RadioGroup
I have a design like multiple options.
[
{
"option": {
"id": 4,
"name": "Size"
},
"values": [
{
"products_attributes_id": 243,
"id": 18,
"value": "XL",
"price": "0.00",
"price_prefix": "+"
},
{
"products_attributes_id": 245,
"id": 19,
"value": "L",
"price": "0.00",
"price_prefix": "+"
},
{
"products_attributes_id": 246,
"id": 20,
"value": "M",
"price": "0.00",
"price_prefix": "+"
},
{
"products_attributes_id": 247,
"id": 21,
"value": "S",
"price": "0.00",
"price_prefix": "+"
},
{
"products_attributes_id": 248,
"id": 22,
"value": "XXL",
"price": "20.00",
"price_prefix": "+"
}
]
},
[![\]
My Coding to show RadioGroup -
<RadioGroup
style={{flexDirection: 'row'}}
size={20}
thickness={2}
color="#144693"
selectedIndex={0}
// onSelect={(item) => onSelect(item, i++)}
>
{item.values.map((c, i) => (
<RadioButton value={c}>
<Text>{c.value}</Text>
</RadioButton>
))}
</RadioGroup>
Showing like this.
Now there are two attributes Size and Color, there may by n- numbers of attributes.
How to get the values of each group ?
Something like - Array ( [0] => 001 [1] => 101 )
I don't know if I understood perfectly, but from what I understand you can get value on onSelect callback, it is called with two arguments, index and value when you click in an option.
<RadioGroup
style={{flexDirection: 'row'}}
size={20}
thickness={2}
color="#144693"
selectedIndex={0}
onSelect={(index, value) => console.log(index, value)} // --> here
>
{item.values.map((c, i) => (
<RadioButton value={c}>
<Text>{c.value}</Text>
</RadioButton>
))}
</RadioGroup>
That lib don't have a method o property get all the values. You can look here.
As a workaround if you are using map in each group to render the items maybe you can add a new property in your object schema to keep track of the selected items or creating an state to track the values.

how can I pass the props (id in particular) down to another component?

This is my first attempt at creating a react native project (with redux as well) and I have a question relating to passing down info. I have an API that looks like this :
[
{
"id": 1,
"name": "Module 1",
"topics": [
{
"id": 1,
"name": "Iterators and Helpers",
"course_id": 1
},
{
"id": 2,
"name": "Object Oriented Ruby",
"course_id": 1
},
{
"id": 3,
"name": "One to Many Relationships",
"course_id": 1
},
{
"id": 4,
"name": "Many to Many Relationships",
"course_id": 1
},
{
"id": 5,
"name": "Active Record Basics",
"course_id": 1
},
{
"id": 2,
"name": "Module 2",
"topics": [
{
"id": 9,
"name": "Introduction to Sinatra",
"course_id": 2
},
{
"id": 10,
"name": "Sinatra CRUD",
"course_id": 2
},
{
"id": 11,
"name": "Sinatra Associations",
"course_id": 2
},
{
"id": 12,
"name": "Introduction to Rails",
"course_id": 2
},
{
"id": 13,
"name": "Rails Forms + CRUD",
"course_id": 2
},
{
"id": 14,
"name": "Rails Associations + CRUD",
"course_id": 2
},
{
"id": 15,
"name": "Rails Sessions and Cookies",
"course_id": 2
},
{
"id": 16,
"name": "Rails Authentication and Authorization",
"course_id": 2
},
{
"id": 17,
"name": "Module 2 Project Guidelines",
"course_id": 2
}
]
{
"id": 3,
"name": "Module 3",
"topics": [
{
"id": 18,
"name": "Introduction to JavaScript",
"course_id": 3
},
{
"id": 19,
"name": "Introduction to Document Object Model",
"course_id": 3
},
{
"id": 20,
"name": "JavaScript Events",
"course_id": 3
},
{
"id": 21,
"name": "JavaScript Asynchronous Functionality + Fetch & CRUD",
"course_id": 3
Each 'module' has many topics. I want the Modules to appear on one screen and the topics for each course to appear once a button is clicked. I have this so far:
render(){
console.log(this.props.courseNames)
return(
<FlatList style={styles.flatlist} keyExtractor={(item)=> item.id} data={this.props.courseNames} ItemSeparatorComponent = { this.FlatListItemSeparator }
renderItem={({item}) => {
return <TouchableOpacity><Button title={item.name} onPress={() => this.props.navigation.navigate('Topics')} style={styles.listitem}/></TouchableOpacity>
}}
ListHeaderComponent = {this.header}/>
)
}
}
This is just a snippet but I'm wondering how I can pass down the information specific to that class so that I can retrieve all the topics that it contains and display them on the next screen. Any pointers would be great! thanks!
I think you're asking how to pass 'parameters' to navigation routes, which, yes, do render components that can receive props from the navigation route parameter.
In your case,
this.props.navigation.navigate('Topics')
should be changed to;
this.props.navigation.navigate('Topics', {id:item.id})
Once you navigate to your Topics route, that component will be able to read the 'id' value from;
props.route.params.id
Route parameters will be any object passed after the route name in this.props.navigation.navigate method.

Iterating on native base Tabs returns Invariant Violation

I am using native base Tabs from the original docs (a copy-paste). I am trying to iterate through the Tabs from an axios response. The json looks a little like this (short version):
{
"categories": [
{
"id": 21,
"user_id": 1,
"category_id": 5,
"lang_id": 9,
"restaurant_id": 1,
"name": "主菜",
"image": null,
"deleted_at": null,
"created_at": "2019-08-28 14:41:11",
"updated_at": "2019-08-28 17:39:47",
},
{
"id": 26,
"user_id": 1,
"category_id": 6,
"lang_id": 9,
"restaurant_id": 1,
"name": "甜品",
"image": null,
"deleted_at": null,
"created_at": "2019-08-28 14:41:32",
"updated_at": "2019-08-28 17:39:50",
},
{
"id": 31,
"user_id": 1,
"category_id": 7,
"lang_id": 9,
"restaurant_id": 1,
"name": "饮料",
"image": null,
"deleted_at": null,
"created_at": "2019-08-28 14:41:50",
"updated_at": "2019-08-28 17:39:54",
}
]
}
And in my component, I am doing this:
render() {
return (
<Container>
<Header hasTabs />
<Tabs>
{
this.state.categories.map((c) => {
return (
<Tab heading="test">
<Text>{c.name}</Text>
</Tab>
)
})
}
</Tabs>
</Container>
);
}
The category state contains the json as it is. Here is the error it returns.
I do not understand the error as there are no styling. From what I understand, it is style related right? Any help is appreciated.
Solved the issue. The problem was that tabs were being rendered before the data was loaded. So in order to fix that, create a isLoading state and put an if statement to check if it has been loaded. The error is because the <Tabs> has no child and it was null I suppose.
Hope this fixes someone else with the same issue.

React-Native MapBox Clustering with custom icons

How to perform clustering in React Native Mapbox with custom icons.
i have checked the earthquake clustering example given on GitHub page of mapbox react native. but i need something different like, i need to do clustering with custom icons. i have 2 types of data/points on map one is user and other is events both have different icons so i need to render those custom icons in clustering.
also on tap of that icon i need to show a pulse animation behind that icon. any possible way to do this?
here is my code for implementing mapbox :-
<MapboxGL.MapView
ref={(ref) => this.map = ref}
showUserLocation={store.homeStore.locationAlowed}
zoomLevel={11}
pitch={45}
centerCoordinate={[store.userStore.longitude, store.userStore.latitude]}
userTrackingMode={MapboxGL.UserTrackingModes.follow}
styleURL={MapboxGL.StyleURL.Street}
style={{
position: store.homeStore.mapPosition,
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
logoEnabled={false}
compassEnabled={false}
attributionEnabled={false}
onDidFinishRenderingMapFully={() => this.map.takeSnap(true).then((resp) => {
if (resp) {
store.homeStore.mapImageSource = resp;
}
})}
onPress={this.onMapPress.bind(this)}>
{store.homeStore.setLocationOnMap && store.homeStore.eventData.length > 0 ?
store.homeStore.eventData.map((prop, key) => {
return (
<MapboxGL.PointAnnotation
key={prop.id}
id={prop.id}
coordinate={[parseFloat(prop.evt_longitude), parseFloat(prop.evt_latitude)]} >
<TouchableOpacity onPress={this.selectEventOnMap.bind(this, prop)} style={{ height: vh * 0.109 }}>
<View style={styles.likesContainer}>
<Image source={require('../Images/ic_home_event_likes.png')}
style={[styles.heartImage, prop.event_likes > 999 ? { marginLeft: vw * 0.018 } :
prop.event_likes > 9 ? { marginLeft: vw * 0.036 } : { marginLeft: vw * 0.049 }]} />
<Text style={[styles.likesText, prop.event_likes < 10 ? { marginLeft: 2 } : '']}>
{prop.event_likes > 999 ? (Math.round(prop.event_likes / 1000) + " k") : prop.event_likes}</Text>
</View>
<Image source={require('../Images/ic_home_inactive_event_pin.png')}
style={{
height: vh * 0.098, width: vw * 0.15, marginTop: vh * 0.017,
tintColor: (prop.userid == store.userStore.id ? Colors.Blue : Colors.warmPink)
}} />
<Image source={this.getImageSource(prop.evt_category)}
style={{
height: vh * 0.041, width: vw * 0.077,
top: vh * 0.035, left: vw * 0.038, position: 'absolute'
}} />
{prop.selected && <Pulse style={{ zIndex: -1, position: 'absolute', top: -((vh * 0.109) / 3) }}
color={Colors.warmPink} numPulses={6} diameter={100} speed={18} duration={1000} />}
</TouchableOpacity>
</MapboxGL.PointAnnotation>
);
}) : null}
{store.homeStore.setLocationOnMap && store.homeStore.peopleData.length > 0 ?
store.homeStore.peopleData.map((prop, key) => {
return (
<MapboxGL.PointAnnotation
key={prop.userid}
id={prop.userid}
coordinate={[parseFloat(prop.longitude), parseFloat(prop.latitude)]} >
<TouchableOpacity onPress={() => { store.homeStore.showProfileCard = true; store.homeStore.userData = prop; }}>
<View style={{
height: vw * 0.130, width: vw * 0.130, borderRadius: (vw * 0.130) / 2,
backgroundColor: Colors.Blue, alignItems: 'center', justifyContent: 'center'
}}>
<AsyncImage source={{ uri: prop.image }}
style={{
height: vw * 0.122, width: vw * 0.122, borderRadius: (vw * 0.122) / 2
}} placeholderColor='#b3e5fc' />
</View>
</TouchableOpacity>
</MapboxGL.PointAnnotation>
);
}) : null}
{this.renderRoute()}
{/* <MapboxGL.ShapeSource
id='earthquakes'
cluster
clusterRadius={50}
clusterMaxZoom={14}
url='http://moso.appinventive.com/public/accesscsv/data.json'>
<MapboxGL.SymbolLayer
id='pointCount'
style={layerStyles.clusterCount} />
<MapboxGL.CircleLayer
id='singlePoint'
filter={['!has', 'point_count']}
style={layerStyles.singlePoint} />
</MapboxGL.ShapeSource> */}
{/* <MapboxGL.ShapeSource
id='talesMarkers'
shape={jsonData}
cluster
clusterRadius={50}
clusterMaxZoom={14}
>
<MapboxGL.SymbolLayer key='{id}' id='{id}' style={styles.icon} />
</MapboxGL.ShapeSource> */}
</MapboxGL.MapView>
and here is the json data :-
const jsonData = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"id": "27",
"evt_name": "nh24 event",
"evt_latitude": "28.624134137261",
"evt_longitude": "77.399671500871",
"evt_start": "1520855452",
"evt_category": "1",
"event_address": "Pusta Road, Bahrampur, Noida, Uttar Pradesh 203207, India",
"evt_createdon": "1520855452",
"userid": "23",
"image": "https://appinventiv-development.s3.amazonaws.com/moso%2FnCA3HzIs7OsAVLYVJ6Db",
"event_likes": "0",
"event_followers": "0",
"distance": "2.6069925023499723",
"view": false,
"event_growth": 0,
"owner_popularity": 0,
"viral": 0,
"icon": 'airport-15'
},
"geometry": {
"type": "Point",
"coordinates": [
77.399671500871,
28.624134137261,
6.55
]
},
"id": "27"
},
{
"type": "Feature",
"properties": {
"id": "26",
"evt_name": "event with exact address",
"evt_latitude": "28.611121352303",
"evt_longitude": "77.385811577333",
"evt_start": "1520839916",
"evt_category": "1",
"event_address": "Sector 65, Noida, Uttar Pradesh 201301, India",
"evt_createdon": "1520839916",
"userid": "23",
"image": "https://appinventiv-development.s3.amazonaws.com/moso%2FnCA3HzIs7OsAVLYVJ6Db",
"event_likes": "0",
"event_followers": "0",
"distance": "1.489932977056515",
"view": false,
"event_growth": 0,
"owner_popularity": 0,
"viral": 0,
"icon": 'airport-15'
},
"geometry": {
"type": "Point",
"coordinates": [
77.385811577333,
28.611121352303,
1.67
]
},
"id": "26"
},
{
"type": "Feature",
"properties": {
"userid": "13",
"name": "",
"username": "howdy",
"latitude": 28.577006492753625,
"longitude": 77.32924537095796,
"facebookprof": "",
"instaprof": "",
"image": "https://appinventiv-development.s3.amazonaws.com/moso%2FchMzFARwXj2z1y3MYASk",
"createdon": "1519757532",
"user_bio": "",
"user_likes": "1",
"user_followers": "1",
"distance": "0.021139920338468652",
"liked": false,
"follows": false,
"view": false,
"live_events": "0",
"user_growth": 1.3149888133309905e-9,
"user_popularity": 0.00046882325363338024,
"viral": 1.1720601065666707e-8,
"icon": 'airport-15'
},
"geometry": {
"type": "Point",
"coordinates": [
77.32924537095796,
28.577006492753625,
77.7
]
},
"id": "13"
},
{
"type": "Feature",
"properties": {
"userid": "20",
"name": null,
"username": "otheruser",
"latitude": 28.606038365831,
"longitude": 77.362243836846,
"facebookprof": "",
"instaprof": "",
"image": "https://scontent.xx.fbcdn.net/v/t1.0-1/c59.0.200.200/p200x200/10354686_10150004552801856_220367501106153455_n.jpg?oh=f621f9474a63f5b27b0514adda5db42b&oe=5B0F8625",
"createdon": "1519776475",
"user_bio": "",
"user_likes": "1",
"user_followers": "1",
"distance": "0.019360181909683884",
"liked": false,
"follows": false,
"view": false,
"live_events": "0",
"user_growth": 1.3149888133309905e-9,
"user_popularity": 0.0000017414245723714283,
"viral": 4.35553391414857e-11,
"icon": 'airport-15'
},
"geometry": {
"type": "Point",
"coordinates": [
77.362243836846,
28.606038365831,
1.6
]
},
"id": "20"
},
{
"type": "Feature",
"properties": {
"userid": "23",
"name": "vijay",
"username": "vijaysharma",
"latitude": 28.577006492753625,
"longitude": 77.32924537095796,
"facebookprof": "https://www.gmail.com",
"instaprof": "https://www.gmail.com",
"image": "https://appinventiv-development.s3.amazonaws.com/moso%2FnCA3HzIs7OsAVLYVJ6Db",
"createdon": "1520588433",
"user_bio": "Usheiwhwosbwowgwiwgwowwjai9a7292ue8rgdidbdidhndjdjdjdjsksoa9wub3829283yehs8dyv3i38sieh3i39w83hejwuhe",
"user_likes": "0",
"user_followers": "0",
"distance": "0.021139920338468652",
"liked": false,
"follows": false,
"view": false,
"live_events": "0",
"user_growth": 0,
"user_popularity": 0,
"viral": 0,
"icon": 'airport-15'
},
"geometry": {
"type": "Point",
"coordinates": [
77.32924537095796,
28.577006492753625,
44.5
]
},
"id": "23"
}
]
}
with pointAnnotations i am able to show points on map but this way clustering is not performed on mapbox. and if i try to make points on map from clustering using shapesource layer and json data then i am not getting how to use my custom icons. also i need to fire a click event on tap of that custom pin and show pulse loading animation behind that point.
please take a look at screenshots also what i need to do with clustering.
screenshots shown only point annotations with which clustering is not happening.
mapbox point annotations without clustering

FlatList react native

I have a problem with FlatList, I can't scroll my list ...
It's block, and my list is enough fat for scrolling
const tab_ad = [
{"id": 0, "Price": 100000, "key": 0},
{"id": 1, "Price": 100000, "key": 1},
{"id": 2, "Price": 100000, "key": 2},
{"id": 3, "Price": 100000, "key": 0},
{"id": 4, "Price": 100000, "key": 1},
{"id": 5, "Price": 100000, "key": 2},
{"id": 6, "Price": 100000, "key": 0},
{"id": 7, "Price": 100000, "key": 1},
{"id": 8, "Price": 100000, "key": 2},
]
export default class Event extends Component {
renderItem(item) {
return (
<Image source={path_default_picture} style={{width: 50, height: 50, margin: 5}}/>
);
}
render() {
return (
<View style={{flex: 1}}>
<FlatList
horizontal
data={tab_ad}
renderItem={(item) => this.renderItem(item)}
keyExtractor={(item, index) => index}
/>
</View>
);
}
react-native-cli: 2.0.1
react-native: 0.49.3
SomeOne can help me ?
FlatList ignores the values that have the same key. I found that after playing a little bit. Most likely the issue is not that the scroll is not enabled but that you have similar values.
Could you please try making sure the key is unique across all the list?
If not, please make a snack with the issue