How do i fill and remove an item into an array depending on its state? - react-native

i am developing an React Native Android App.
I am receiving data (id and name) from my API. Now i am using a ListView with MKIconToggle (react-native-material-kit) to display my list data.
With MKIconToggle i can give my displayed items two different states (clicked = color is black / unclicked = grey). Now i want to send the list of clicked items back to my server. But i just can´t figure out how i put the clicked items for example into an array or something and only send clicked items to server.
My RenderMethod with the ListView looks like this:
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderList}
horizontal={true}
renderHeader={this.renderHeader}
/>
RenderList:
<View
style={{justifyContent: 'flex-start', alignItems: 'center', padding: 10, flexDirection: 'column'}}>
<MKIconToggle
checked={this.state.initialChecked}
onCheckedChange={()=>this._onIconChecked(data)}
onPress={this._onIconClicked}
style={{flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}>
<Text state_checked={this.state.checkedState}
pointerEvents="none"
style={styles.titleChecked}
numberOfLines={3}>{data.name}</Text>
<Text pointerEvents="none"
style={styles.title}
numberOfLines={3}>{data.name}</Text>
</MKIconToggle>
</View>
Now i should handle my clicked Items in _onIconChecked:
_onIconChecked: function (data) {
// Put data.id into an array, if it way clicked (state is true)
// If date.id is unclicked again, then remove from array
},
I hope i could explain my issue clearly, otherwise just let me know. I am new in programming and writing stackoverflow issues/questions, so please give me hints if i made something wrong.

From your information I will have to make a few assumptions in order to be able to answer your question.
For now I will assume that that checked handler properly returns the 'id' of an item that is the same id as in your array of items.
So assuming your array is:
[{name: 'Luke', id: 1'}, {name: 'Darth', id: 2'}]
If I were to click on 'Luke' _onIconChecked would receive a data object that at least has id: 1 in it.
The second assumption is that you have an array somewhere where you can store those clicked items. I would just put that outside of your component seeing as MK would already take care of properly rendering a checked item. So:
var _checkedItems = []
var myComponent = React.create...
The last assumption is that the data object passed to _onIconChecked also contains information on the state of the checkbox, so date.checked is either true or false.
The precise implementation might be different for all these items, but this is what I can work off of.
Now what you could do is:
_onIconChecked: function (data) {
var id = data.id;
var checked = data.checked;
var currentIndex = _checkedItems.indexOf(id)
if(checked) {
if(currentIndex == -1) { _checkedItems.push(id) }
// the 'else' would mean the item is already in the array, so no need to add
} else {
if(currentIndex > -1) {
// This means that the item is in the array, so lets remove it:
_checkedItems.splice(currentIndex, 1) // This removes the id from the array.
}
}
}
What you'd do now to only get the items from your this.state.items array that have their ids in the checked array:
getCheckedItems: function() {
return this.state.items.map(function(item) {
if(_checkedItems.indexOf(item.id) > -1){
return item
}
})
}
I am not sure about your setup so I made lots of assumptions and probably over engineered some things, but it might get you going in the right direction.

Related

In react-native-google-places-autocomplete , there is a method to set the inputs initial value, but it doesn't trigger the search query

I am trying to pass a saved search term string to prefill into google places autocomplete's input field. The setAddressText method they offer successfully prefills the input, but it does not trigger the search, so no dropdown options open. Only once you type something does the query run, so its obviously listening for an onChangeText event before it runs the query. I therefore don't see the point in the setAddressText method, if you then have to type again anyway. Surely there must be a way to trigger the search, without having to add / takeaway characters manually with the keyboard from the existing search term.
const { googleApiKey } = config
const ref = useRef()
useEffect(() => {
ref.current?.setAddressText(initialValue)
}, [])
return (
<View sx={{ flex: 1 }}>
<GooglePlacesAutocomplete
ref={ref}
placeholder={placeholder}
listViewDisplayed="true"
fetchDetails={true}
textInputProps={{
autoFocus: true,
...sx
}}
onPress={(data, details = null) => {
console.log("data", data, "details", details)
}}
query={{
key: googleApiKey,
language: "en",
components: "country:gb",
types: types ? types : null
}}
/>
</View>
)
}
Any wisdom on this would be greatly appreciated!
Full Disclosure: I maintain this library.
This is not currently supported by the library.
There is a feature request open here.

Grid View With different Hight and width in react Native

enter image description here
Can anyone give idea how I can create this design in React-Native
here is the design image
Your array -
[item1, item2, item3, ....]
Modify it as -
[
{id, type:1, data:[item1, item2, item3] },
{id, type:2, data:[item4, item5, item6] },
{id, type:3, data:[item7, item8, item9] },
{id, type:1, data:[item10, item11, item12] }
{id, type:2, data:[item13, item14, item15] }
...
...
]
Like, Each item will have a type field and array of 3 items..
Use this data inside flatlist or scrollview and you can classify it according to the type(1,2,3) field.
If type == 1
return below component.
If type == 2
return
If type == 3
return
So the final result will look like what you are expecting..!
It's just an idea! Try to implement.
For better performance you can build data in this format before sending from the backend.(if the data is coming as part of any APIs)
data format function
const modifyData = (arr) => {
let finalData = [];
for (let i=0; i < arr.length; i+=3){
let j = 0;
let data = []
while(j<3){
arr[i+j] && data.push(arr[i+j]);
j+=1;
}
finalData.push({id: Math.random().toString(), type: (i/3)%3 + 1, data})
}
return finalData;
}
use some random id generator for id (crypto or Math.random().toString())
I found a similar thread hope this helps
Grid layout with different height items (React Native)
The markup will look like this:
<View style={styles.wrapper}>
<ScrollView contentContainerStyle={styles.container}>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.dataSourceColumn1}
/>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.dataSourceColumn2}
/>
<ListView
contentContainerStyle={styles.list}
dataSource={this.state.dataSourceColumn3}
/>
</ScrollView>
</View>
Wrapper View will help you stretch the block to fit the entire area. From the styling point of view you can resolve the task with flexbox:
wrapper: {
flex: 1
},
container: {
flexDirection: 'row',
paddingHorizontal: 5
},
list: {
flex: 1,
flexDirection: 'column',
paddingVertical: 10,
paddingHorizontal: 5
}
The trick is that we treat every column as a row inside the container. Play around with paddings and alignItems styling to achieve consistent spacing.
Note that the handy onEndReached that comes with the ListView won't be available here, so you'll have to catch the user reaching the end of the ScrollView in order to know when new fetch is required. But that's a different question which I believe has already been answered elsewhere.
In case the grid is finite and you don't need to throw more items into it, things are simpler. Just split the data the way described above and use 3 View-s with nested items instead of the ListView-s.
Now you can edit as per your requirements and easily find the way through this.

React-native - How to create a scrollable flatList in which the chosen item is the one at the middle?

I would like to create a scrollable FlatList to select only one item among a list. After the user scroll the list, the selected item will be the one in the colored rectangle (which have a fixed position) as you can see here :
Actually I'm only able to render a basic FlatList even after some researches.
Do you know how I should do that ?
I found the solution (but it's not a FlatList) !
To do that I use :
https://github.com/veizz/react-native-picker-scrollview.
To define the background of the current selected items I added a new props highLightBackgroundColor in the ScrollPicker Class in the index file of react-native-picker-scrollview :
render(){
...
let highLightBackgroundColor = this.props.highLightBackgroundColor || '#FFFFFF';
...
let highlightStyle = {
...
backgroundColor: highLightBackgroundColor,
};
...
How to use it :
<ScrollPicker
ref={sp => {
this.sp = sp;
}}
dataSource={['a', 'b', 'c', 'd', 'e']}
selectedIndex={0}
itemHeight={50}
wrapperHeight={250}
highLightBackgroundColor={'lightgreen'}
renderItem={(data, index, isSelected) => {
return (
<View>
<Text>{data}</Text>
</View>
);
}}
onValueChange={(data, selectedIndex) => {
//
}}
/>
How it looks without others customizations:
You can implement the same setup with the very popular react-native-snap-carousel package, using the vertical prop. No need to use a smaller, poorly documented/unmaintained package for this.

React Native for loop with Array not doing what I expected

I'm trying out some things in React Native for the first time and i'm trying to roll 3 dices (text based for now).
I'm using a for loop to go over an array of the 3 dices. However i'm only seeing one dice text being updated (the 3rd one).
Also when doing some alerts to check what's going on within that for loop, i'm seeing unexpected things? the first alert says 2, the second alert says 1 and then it usually no longer alerts, seldom it also alerts a third time with a 0.
My code so far:
(file: Game.js)
import React from 'react'
import { StyleSheet, Image, Text, View, Button } from 'react-native'
export default class Home extends React.Component {
state = {
dices: [null, null, null],
rollsLeft: 3,
keepDices: [false, false, false],
}
//When this component is mounted (loaded), do some defaults
componentDidMount() {
}
//Roll dices
rollDices = () => {
for(let i = 0; i < 3; i++){
alert('for loop at ' + i);
//Math random to get random number from rolling the dice
randomNumber = Math.floor(Math.random() * 6) + 1;
//Check if the user wanted to keep a dice's value before reassigning a new value
if(this.state.keepDices[i] === false){
//User want to roll this dice, assign new random number to it
//this.setState.dices[i] = randomNumber;
let newDices = [ ...this.state.dices ];
newDices[i] = randomNumber;
this.setState({ dices : newDices });
}
}
//Deduct 1 roll from total
this.setState.rollsLeft--;
//TODO: Check if rolls equals 0, then make player2 active!
}
render() {
return (
<View style={styles.container}>
<Text> {this.state.dices[0]} ONE </Text>
<Text> {this.state.dices[1]} TWO</Text>
<Text> {this.state.dices[2]} THREE</Text>
<Text>Turns left: {this.state.rollsLeft} </Text>
<Button
title="Roll 🎲"
onPress={this.rollDices} />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center'
},
})
In React Native the setState function is asynchronous.
Meaning that this.setState({ dices : newDices }); can end up setting dices to different values depending on which finishes first.
If you want to control what happens after you use setState, you can call a function after the set is done like this
this.setState({dices: newDices}, () => {
// Do something here.
});
There is some really useful information on calling function after the setState here: Why is setState in reactjs Async instead of Sync?
and some good explanations of how setState in react works and how to get around it here: https://medium.com/#wereHamster/beware-react-setstate-is-asynchronous-ce87ef1a9cf3
Together with DCQ's valuable input for async setStates bundling I also noticed that i'm always resetting the copied dice array within the for loop and thus only saving my last dice correctly.
Next up the for loop was actually counting right from 0 to 2 however the alert boxes don't interrupt the code as i'm used to in the browser therefore it looked a bit off. When doing console.log (which is also cleaner and more correct logging) I noticed things did went right there.

Settings different Values of element on a state

So in my react native, I have a spinner which I am using to enter numbers. It has two buttons which increases or decreases a value. But the problem is that I have to set the value to a state and I have multiple elements. So if I change the value of one element, everything else changes too.
Here is the Package
And here is a sample code I am working with:
this.state = {
qty: null,
}
<InputSpinner
max={50}
min={1}
step={1}
width={100}
height={50}
colorMax={"#2a292d"}
colorMin={"#2a292d"}
buttonFontSize={13}
value={this.state.qty}
onChange={(num) => {
this.setState({qty: num});
}}/>
So on change I am settings the qty state. But I have multiple spinners and changing one changes everything because each uses the same state. What would be the better solution for this? Should I use an array to store each item qty?
For me the better solution is assign at each Spinner an ID and then create an object with key = spinnerID and value = num
this.state = {
qty: {},
}
<InputSpinner
max={50}
min={1}
step={1}
width={100}
height={50}
colorMax={"#2a292d"}
colorMin={"#2a292d"}
buttonFontSize={13}
value={this.state.qty['1'] || 1}
onChange={(num) => {
let qty = Object.assign({}, this.state.qty);
qty['1'] = num;
this.setState({qty});
}}/>
yes, obviously you need to maintain multiple states for each spinner, never use one state for that. I would recommend to use an array like
`
this.state = {
spinnerValues:[]
}
`
and onChange of that input spinner you can do somewhat like
`
onChange={(num) => {
let currentState = this.state.spinnerValues;
currentState[i] = num; // here i is the index which you will provide for the spinner num
this.setState({spinnerValues: currentState});
`
and for value of each spinner
value = {this.state.spinnerValues[i]}