So I have this selection FlatList where the user can select a country. When I press on a item it's going to take a second and after the second it is displaying the checkmark.
The Problem is the second. The user cannot wait a second to see that the country was selected.
<FlatList
keyExtractor={item => item.countryid}
data={countryChoices}
renderItem={({item}) => {
return(
<CountryComponent
item={item}
conditionToCheck={country == item.countryname}
onPress={() => setCountry(item.countryname)}
/>
)
}}
/>
This is my Flatlist. countryChoices is just an array with different objects for the countries. the conditionToCheck checks wether to show or to hide the checkmark. If the selected Country is equal to the item then it's going to show the checkmark.
But after clicking on it it's taking too long :/
I also tried wrapping the FlatList Item in a useCallback but it wasn't (much) faster
Try passing country as extraData in you FlatList since country is outside of data prop
<FlatList
keyExtractor={item => item.countryid}
data={countryChoices}
extraData={country}
renderItem={({item}) => {
return(
<CountryComponent
item={item}
conditionToCheck={country == item.countryname}
onPress={() => setCountry(item.countryname)}
/>
)
}}
/>
extraData is a marker property for telling the list to re-render (since it implements PureComponent). If any of your renderItem, Header, Footer, etc. functions depend on anything outside of the data prop, stick it here and treat it immutably.
Related
I am using react-virtualized to create an infinite scroll in my React app. Because list items can be of different heights, I am using CellMeasurer from react-virtualized to render list items. I also have an intersection observer that listens for scroll and loads more data as user scrolls down. The code looks like this:
const rowRenderer = ({ key, index, style, parent }) =>
<CellMeasurer
cache={cache.current}
parent={parent}
columnIndex={0}
rowIndex={index}>
<ListItem
key={key}
listData={listData[index]}
style={style}
setObserver={setObserver}
/>
</CellMeasurer>
<AutoSizer>
{
() => ({ width, height }) =>
<List
width={width}
height={height}
rowHeight={cache.current.rowHeight}
deferredMeasurementCache={cache.current}
rowCount={listData.length}
rowRenderer={rowRenderer}
/>
}
</AutoSizer>
This works fine except React gives a warning that each item of List should have a unique key. If I move the key={key} to CellMeasurer from ListItem to fix this, the warning goes away but the code doesn't load new data anymore on scroll.
I am not sure why this is happening?
The app also allows deleting a list item from the list. However, when the deletion happens, the list scrolls down by a significant number of rows, rather than staying at that scroll position. How do I fix this?
I'd like to create a basic "setting toggle" component, with Title and Subtitle on the left, and a Switch on the right. I'd like to be able to switch the toggle when the whole component is clicked, not just when the switch is.
In order to achieve this is wrapped the component in a Touchable and execute the supplied onValueChange callback, so the container component can handle the state change of the switch.
export default function SettingToggle({
title,
subtitle,
toggled,
onValueChange,
}) {
return (
<TouchableWithoutFeedback
style={styles.container}
onPress={() => onValueChange(!toggled)}
>
<View>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
<Switch
value={toggled}
onValueChange={value => onValueChange(value)}
></Switch>
</TouchableWithoutFeedback>
)
}
Now when I click the Switch, it animates nicely to the other value, but when click the component, the whole component redrawn with the new value of {toggled}, thus on the UI it feels like the switch is instantly changing to the other value.
Question 1: How could I preserve the animation even when the component is clicked, and not just the Switch?
Question 2: From where does React know, that it doesn't need to redraw the view when only the Switch is clicked? The render() method is called, as the parent component's state changes with the onValueChange call, so the SettingToggle is rerendered with a new {toggled} value. I assume the view is "recreated" but under the hood React probably isn't changing the view in the hierarchy with the newly created one, as it somehow knows that it is not needed. How does this work?
I have recently started using react-native and have come across the FlatList component. When using react I have always used map with an array.
I was using FlatList but there was issues when I wanted to change the flex-direction of items in the FlatList so I reverted to using map.
Here are the two examples using both methods:
map
{
this.state.images.map(image => {
return (
<UsersImage key={ image } source={{ uri: image }} />
)
})
}
FlatList
<FlatList
data={ this.state.images }
renderItem={({item}) => {
return (
<UsersImage source={{ uri: item }} />
)
}}
keyExtractor={(item, index) => index}
/>
Can anyone explain why one should use FlatList over map or vice versa?
FlatList has lazy loading (it only shows what's on screen, so it can be more performant if you have a huge list). BTW you can get it to be horizontal if that's what you needed to change the flex direction for - just pass the horizontal prop (equivalent to saying horizontal={true})
The FlatList displays the similarly structured data in a scrollable list. It works well for large lists of data where the number of list items might change over time. The FlatList shows only those render elements that are currently displaying on the screen, not all the elements of the list at once. So that's the main reason FlatList can handle a large set of data with a very complex view easily.
The map() function is used to iterate over an array and manipulate or change data items. In React, the map() function is most commonly used for rendering a list of data to the DOM.
In react-native FlatList is recommended over map() when we need to display a large scrollable list.
no need to flex your View tags. just add horizontal
<FlatList
horizontal
data={data}
renderItem={(item) => this.renderItem(item.item)}
keyExtractor={(item, index) => index}
/>
I'm new to react-native so this.setstate method is not predictable for me.
I'm selecting a list of Venue on dropdown 1
according to the venue , the number of available days must be shown as options on the second dropdown.
and similarly according to the second one i have to set timeslots avaiable on the third dropdown
the 2nd to 3rd dropdown works fine for me
but when i select the venue on the first dropdown the 2nd one does not updates. this .setstate is working late there
if i select the venue once more the previously selected days loads not the current one. like setstate method is lagging one step behind
Must be the way i wrote the code ,
I am open to corrections, new structure of coding , anything
but very much in need to get this work
onVenueSelect(index,value){
var props=this.props;
console.log('On venue Select................................')
console.log('index'+index)
console.log('value'+value)
console.log(this.state.venue_id_array[index])
props.getFixtureSlots(this.state.venue_id_array[index], this.state.game_type, this.state.game);
this.setState({selected_venue_id:this.state.venue_id_array[index]})
var days=[];
var timeslots=props.GETFIXTURETIME.timeslot;
for(var i in timeslots){
days.push(timeslots[i].day_of_week);
}
this.setDay_array(days);
this.refs.modal_dayselect.select(-1);
this.setState({selected_venue:value});
}
onDaySelect(index,value){
this.refs.modal_hrsselect.select(-1);
this.props.getFixtureSlots(this.state.selected_venue_id, this.state.game_type, this.state.game);
var props=this.props;
this.setState({selected_day_no:this.state.day_no_array[index]})
console.log(this.state.day_no_array[index])
this.setState({selected_day:value})
}
render_center_selection(){
return(
this.props.selecteddays_array.map((a, i) => {
return( <View key={i} style={{ height:40, borderBottomWidth:2, borderBottomColor: '#ededed' }}>{
<View style={{flexDirection:'column'}}>
<View style={{flexDirection:'row'}}>
<ModalDropdown
style={styles.selection}
defaultValue='Venue'
textStyle={{width:200,fontSize:20,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.dropdownstyle}
dropdownTextStyle={{width:350,fontSize:20,textAlign:'center',backgroundColor: '#FDD60B',}}
options={this.state.venue_name_array}
onSelect={(index,value)=>{this.onVenueSelect(index,value)}}/>
<ModalDropdown
ref="modal_dayselect"
style={styles.dayselection}
defaultValue='Day'
textStyle={{width:50,fontSize:15,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.daydropdownstyle}
dropdownTextStyle={{width:50,fontSize:15,textAlign:'center',backgroundColor: '#FDD60B',color: '#7070D8'}}
options={this.state.day_array}
onSelect={(index,value)=>{this.onDaySelect(index,value)}}/>
<ModalDropdown
ref="modal_hrsselect"
style={styles.dayselection}
defaultValue='HRS'
textStyle={{width:50,fontSize:15,textAlign:'center',color: '#7070D8'}}
dropdownStyle={styles.daydropdownstyle}
dropdownTextStyle={{width:50,fontSize:15,textAlign:'center',backgroundColor: '#FDD60B',color: '#7070D8'}}
options={this.state.hrs_array}
onSelect={(index,value)=>{this.setState({selected_hr:value})}}/>
</View>
</View>
}</View>);
})
);
}
First thing you have to do is to remove all console.log statements from your code. It really helpful but slows down the app rendering/refreshing rate.
Second thing and the most important thing is to consolidate state setting calls. ie, you only need one setState call inside one action. For every setState call the app re-renders the parts which uses that changed state. So, update multiple states at once otherwise it will not be detected by the react.
My list component should be able to highlight why a certain element is part of the list based on keywords entered by the user.
I am using the react-highlighter component currently inside the list item, but it requires me to send down the keyword entered by the user from the search box => to the listview => to the list item
That doesn't look very react to me.
I am also using redux so I have only one store, and the listview and items are not directly aware of the store. They are dumb components just rendering properties.
<SearchBox onChange={setSearchText} value={searchText} />
<List items={item} highlight={searchText}>
<ListItem>
<Highlight search={searchText}>{name}</Highlight>
</ListItem>
</List>
Is there a more elegant way to handle such highlighting?
As you mentioned in a comment you could pull up your highlight functionality into a HighlightedListItem component.
<SearchBox onChange={setSearchText} value={searchText} />
<List items={item} >
<HighlightedListItem item={item} highlight={searchText}>
{...stuff}
</ListItem>
</List>
In addition when thinking ahead to maximizing performance, this approach might be easier to reason when adding a shouldcomponentupdate
EX:
// HighlightedListItem
shouldComponentUpdate: function(nextProps, nextState) {
return nextProps.item !== this.props.item ||
nextProps.searchText !== this.props.searchText;
}