I am using react-native-swiper-flatlist , but I cannot figure it out how to use scrollToIndex on button press - react-native

I am using react-native-swiper-flatlist , I want to scroll forward to some index by tapping button but no clue how to do it. Although I am very beginner to react native development.
I have searched alot but nothing helps, I get an error of undefined is not an object this2.swiper.scrollToIndex'
render() {
return (
<View style={styles.container}>
<SwiperFlatList
ref={swiper => {
this.swiper = swiper;
}}
data={[
{ key: "a" },
{ key: "b" },
{ key: "c" },
{ key: "d" },
{ key: "e" }
]}
index={0}
renderItem={({ item, index }) => (
<View>
<Image
style={styles.child}
source={require("../../assets/advertisementtwo.png")}
/>
<Image
style={styles.child}
source={require("../../assets/advertisementtwo.png")}
/>
<Image
style={styles.child}
source={require("../../assets/advertisementtwo.png")}
/>
<Image
style={styles.child}
source={require("../../assets/advertisementtwo.png")}
/>
<Button
title={"Next"}
onPress={this.swiper.scrollToIndex(1, true)}
style={{ backgroundColor: "white" }}
/>
</View>
)}
/>
</View>
);
}
Should swipe on button click
Here is the screenshot of the error I am getting

Try adding ref='swiper' as a SwiperFlatList prop,
Example
<SwiperFlatList ref='swiper'/>
this.refs.swiper._scrollToIndex(2)

For those who are using React hook instead of class, you can do sth like that to utilise the scrollToIndex function
//First, make a ref for storing the swiper instance inside your swiper compoent
const swiperRef = useRef<any>({});
//Second, store the reference
<SwiperFlatList
ref={(component) => { swiperRef.current._swiper = component; }}
>
//Later on, you can call the function like this
swiperRef.current._swiper.scrollToIndex({index: 2})

Related

React native, using TouchableOpacity onPress

I just started learning react native. I am currently trying to implement TouchableOpacity on image rendering from an array and use the info for that element from the array to create a new page. The goal of the code is to have a userInfo page that lists all the images and once you tap on an image, it will show details of that user (you will see just this user and no other ones) using userDetails. I know my TouchableOpacity part will not work, but I don't know how to make it work.
This is from my userInfo.js:
const UserInfo =() => {
const users = [
{userName: "A",
imageSource: require("../../assets/users/A.jpg"),
bio: "this is A"
},
{userName: "B",
imageSource: require("../../assets/users/B.jpg"),
bio: "this is B"
},
{userName: "C",
imageSource: require("../../assets/users/C.jpg"),
bio: "this is C"
}
]
return(
<FlatList
showsVerticalScrollIndicator={false}
keyExtractor={(users)=> users.userName}
data={users}
renderItem = {({item})=>{
return <View>
<TouchableOpacity onPress={userInfoLink(users.userName, users.imageSource, users.bio)}>
<View style={styles.viewBox}><Image style={styles.image} source={item.imageSource}/></View>
</TouchableOpacity>
<Text style={styles.text}>{item.userName}</Text>
</View>;
}}
/>
)
};
This is from my userDetails.js:
const UserDetail=({imageSource, userName, bio}) => {
return <View>
<View style={styles.viewBox}><Image style={styles.image} source={imageSource}/></View>
<Text style={styles.text}>User name: {userName}</Text>
<Text style={styles.text}>Bio: {bio}</Text>
</View>;
}
Ok, after doing some research I found a way to make it work. I used navigation.navigate and passing parameters into the page.
Here is my return code in UserInfo.js:
return(
<FlatList
showsVerticalScrollIndicator={false}
keyExtractor={(users)=> users.userName}
data={users}
renderItem = {({item})=>{
return <View>
<TouchableOpacity onPress={()=>{navigation.navigate('UserDetails', {imageSource: item.imageSource, userName: item.userName, bio:item.bio })}}>
<View style={styles.viewBox}><Image style={styles.image} source={item.imageSource}/></View>
</TouchableOpacity>
<Text style={styles.text}>{item.userName}</Text>
</View>;
}}
/>
)
Here is the code in UserDetails.js:
const UserDetail=({navigation}) => {
const imageSource = navigation.getParam('imageSource', 'a no image image');
const userName = navigation.getParam('userName', 'username error');
const bio = navigation.getParam('bio', 'bio error');
return <View>
<Text style={styles.title}>User Detail</Text>
<View style={styles.viewBox}><Image style={styles.image} source={imageSource}/></View>
<Text style={styles.text}>User name: {userName}</Text>
<Text style={styles.text}>Bio: {bio}</Text>
<Button title="User Info" onPress={()=>{navigation.navigate('UserInfo')}}/>
</View>;
}
I am wondering if adding the parenthesis and arrow was what fixed it.
You went from:
onPress={userInfoLink(users.userName, users.imageSource, users.bio)}
To this:
onPress={()=>{navigation.navigate('UserDetails', {imageSource: item.imageSource, userName: item.userName, bio:item.bio })}}

Conditionally style not working in react native

I followed this answer to dynamically style my component.
Here is my render method :
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.images}
numColumns={2}
keyboardShouldPersistTaps={'always'}
keyboardDismissMode={'on-drag'}
keyExtractor={item => item.localIdentifier}
renderItem={({ item, index }) =>
<TouchableHighlight
underlayColor='transparent'
onPress={() => this.openImage(index)}
onLongPress={() => this.startSelection(item)}
>
<View style={[styles.albumContainer, (this.state.selectedItems.indexOf(item)>-1)?styles.selectedItem:styles.unselectedItem]}>
<Image
style={styles.albumThumbnail}
source={item.image}
/>
</View>
</TouchableHighlight>
}
/>
</View>
);
}
As you can see I am displaying image thumbnail with TouchableHighlight and FlatList. When user will press and hold on any image thumbnail I called startSelection() with particular flatlist item which then add that item to state. I used that state to set style dynamically of my image as :
<View style={[styles.albumContainer, (this.state.selectedItems.indexOf(item)>-1)?styles.selectedItem:styles.unselectedItem]}>
<Image
style={styles.albumThumbnail}
source={item.image}
/>
</View>
Here is startSelection() method :
startSelection(item) {
let temp = this.state.selectedItems;
temp.push(item);
this.setState({
selectedItems : temp
});
}
Here is my stylesheet :
const styles = StyleSheet.create({
selectedItem: {
borderWidth: 3,
borderColor: '#22aaff',
},
unselectedItem: {
borderColor: '#000000',
}
});
But when user press and hold that view, item will added to state but style is not changing.
Please help me what's going wrong here !!!
This can be found on FlatList docs:
This is a PureComponent which means that it will not re-render if props remain shallow-equal. Make sure that everything your renderItem function depends on is passed as a prop (e.g. extraData) that is not === after updates, otherwise your UI may not update on changes. This includes the data prop and parent component state.
So you can add extraData to your FlatList component like this:
FlatList Component:
<FlatList
data={this.state.images}
extraData={this.state} //add this!
numColumns={2}
keyboardShouldPersistTaps={'always'}
keyboardDismissMode={'on-drag'}
keyExtractor={item => item.localIdentifier}
renderItem={({ item, index }) =>
<TouchableHighlight
underlayColor='transparent'
onPress={() => this.openImage(index)}
onLongPress={() => this.startSelection(item)}
>
<View style={[styles.albumContainer, (this.state.selectedItems.indexOf(item)>-1)?styles.selectedItem:styles.unselectedItem]}>
<Image
style={styles.albumThumbnail}
source={item.image}
/>
</View>
</TouchableHighlight>
}
/>
P.S: If your component state has variables which should not re-render FlatList, you would be better of using extraData = {this.state.selectedItems}, but then you need to make sure you pass a different reference to selectedItems when you call setState on startSelection. Like this:
startSelection(item) {
let temp = [...this.state.selectedItems];
temp.push(item);
this.setState({
selectedItems : temp
});
}
Wrap them with extra []
style={[styles.albumContainer, [(this.state.selectedItems.indexOf(item)>-1)?styles.selectedItem:styles.unselectedItem]]}

Passing values dynamically to child component react native

App.js
render() {
return (
<View style={{ flex: 1, marginTop: 20 }}>
<Button
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
onPress={() => {
(this.state.dadda = '2017-09-07');
}}
/>
<EventCalendar
eventTapped={this._eventTapped.bind(this)}
events={this.state.events}
width={width}
initDate={this.state.dadda}
scrollToFirst={false}
/>
</View>
); }
This is my parent component ,I want to pass initDate to event calendar component,I want to update the date when the button is pressed?
You should not mutate the state by assigning value to the state variable directly but instead use setState to acheive that.
<Button
title="Learn More"
color="#841584"
accessibilityLabel="Learn more about this purple button"
onPress={() => this.setState({dadda: '2017-09-07'})}
/>
The way you are setting dadaa into the state is not correct, use this.setState function instead, have a look at the doc.
Change your onPress handler to
...
< Button
title = "Learn More"
color = "#841584"
accessibilityLabel = "Learn more about this purple button"
onPress = {
() => {
this.setState({
dadda:'2017-09-07'
});
}
}
/>
...
Also, don't declare the function inside render, rather keep it at the class level like
onPressHandler = () => {
this.setState({
dadaa: 'aaaa'
});
}
render() {
return (
...
<
Button
...
onPress = {this.onPressHandler}
...
/>
...
);
}
Hope this will help!

ReactNative - FlatList not updated until scroll

I have a problem with FlatList component which does not update until scrolled.
I tried add log to renderItem and keyExtractor both methods called with correct data but list didn't update.
Here is a render method:
render() {
const messages = this.props.messages
const message = this.props.message
return (
<View style={[styles.container]}>
<FlatList
ref={"flatList"}
contentContainerStyle={styles.list}
data={messages}
renderItem={(listItem) => {
return <MessageBuble message={listItem.item}/>
}}
keyExtractor={(item: Message) => {
return item.id
}}
/>
<View style={[styles.textInputContainer]}>
<TextInput
style={styles.textInput}
value={message}
multiline={true}
onChangeText={this.props.messageChanged}
/>
<Button title={"Odeslat"} onPress={() => {
if (this.props.sendMessage) {
this.props.sendMessage(this.props.message)
}
}}/>
</View>
</View>
)
}
Add extraData in FlatList and retry
<FlatList
extraData={this.props}
....
Tried the extraData, but that does not work.
There was an issue on Android where content was not visible when I returned back from another page to home screen (where the flatlist was present). The content was visible when I scrolled it a bit.
I assigned the main list to the extraData attribute, and could see that it changed in size via console logs. But the content remained invisible. Finally, used
onContentSizeChange={() => {
if (list.length > 0) {
ref.current.scrollToOffset({ animated: true, x: 0 });
}
}}
and it worked.

Conditional Rendering on Items of Native Base Picker [React Native]

I’m using ‘Native Base’ components for our product and going good with this,
but I’m stuck at one point and it is around putting Items in Nativebase Picker. My code is like this
Render Method code -
render(){
return (
<View style={{marginTop: 20, flexDirection:'row', flexWrap:'wrap', justifyContent:'space-around', alignItems:'center'}}>
<View style={{flex:1, justifyContent:'center', alignItems:'flex-end' }}>
<Button
style={{ backgroundColor: '#6FAF98', }}
onPress={this._showDateTimePicker}
>
<Text>Select Date</Text>
</Button>
</View>
<View style={{flex:1, justifyContent:'center', alignItems:'stretch'}}>
<Picker
style={{borderWidth: 1, borderColor: '#2ac', alignSelf:'stretch'}}
supportedOrientations={['portrait','landscape']}
iosHeader="Select one"
mode="dropdown"
selectedValue={this.state.leaveType}
onValueChange={(value)=>this.setState({leaveType:value,})
//this.onValueChange.bind(this)
}>
<Item label="Full Day" value="leave1" />
{
this.showStartDateFirstHalf() // Here I want to show this picker item on the basis of a condition
}
<Item label="2nd half" value="leave3" />
</Picker>
</View>
<DateTimePicker
isVisible={this.state.isStartDatePickerPickerVisible}
onConfirm={this._handleDatePicked}
onCancel={this._hideDateTimePicker}
mode='date'
/>
</View>
);
}
showStartDateFirstHalf()
{
if(!this.state.isMultipleDays)
{
return(
<Item label="1st Half" value="leave2" />
);
}
}
So, this code is working fine if this.state.isMultipleDays is false, But when this.state.isMultipleDays is true, it means when it is in else part then i'm getting this error -
Cannot read property 'props' of undefined
I think there's an easier answer to this. Instead of creating the separate showStartDateFirstHalf() function try this:
render() {
const pickerItems = [
{
label: 'Full Day',
value: 'leave1',
},
{
label: '1st Half',
value: 'leave2',
},
{
label: '2nd Half',
value: 'leave3',
},
];
const filteredItems = pickerItems.filter(item => {
if (item.value === 'leave2' && this.state.isMultipleDays) {
return false;
}
return true;
});
// The 'return' statement of your render function
return (
...
<Picker ...>
{(() =>
filteredItems.map(item =>
<Item label={item.label} value={item.value} />
)()}
</Picker>
...
);
}
That way, you already have a list of items that is determined before the return statement of the render cycle. Also the use of filter instead of map will not just give you null as the second item if the condition is not met, but will remove the item altogether.