I am learning React native app. I found one demo app from open source app about FlatList where user can click the go down of the screen as well as go up of the screen. I would like implement same logic in SectionList
, According to React native documentation, FlatList and SectionList has almost same props. But when I am try implementing the scroll down and up button logic SectionList, it does not work. It throws me error. Here is the snack-bar they used FlatList Scroll down and scroll up logic.
Here is my failed attempt on SectionList
and Demo
import React from "react";
import {
StyleSheet,
Text,
View,
SafeAreaView,
SectionList,
StatusBar,
TouchableOpacity,
Image,
} from "react-native";
const DATA = [
{
title: "Main dishes",
data: ["Pizza", "Burger", "Risotto"],
},
{
title: "Sides",
data: ["French Fries", "Onion Rings", "Fried Shrimps"],
},
{
title: "Drinks",
data: ["Water", "Coke", "Beer"],
},
{
title: "Desserts",
data: ["Cheese Cake", "Isse Cream"],
},
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const listRef = React.useRef(null);
const [contentVerticalOffset, setContentVerticalOffset] = React.useState(0);
const CONTENT_OFFSET_THRESHOLD = 300;
const upButtonHandler = () => {
//OnCLick of Up button we scrolled the list to top
listRef.scrollToOffset({ offset: 0, animated: true });
};
const downButtonHandler = () => {
//OnCLick of down button we scrolled the list to bottom
listRef.scrollToEnd({ animated: true });
};
return (
<SafeAreaView style={styles.container}>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
onScroll={(event) => {
setContentVerticalOffset(event.nativeEvent.contentOffset.y);
}}
ref={listRef}
/>
<TouchableOpacity
activeOpacity={0.5}
onPress={downButtonHandler}
style={styles.downButtonStyle}
>
<Image
source={{
uri: "https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_down.png",
}}
style={styles.downButtonImageStyle}
/>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.5}
onPress={upButtonHandler}
style={styles.upButtonStyle}
>
<Image
source={{
uri: "https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_up.png",
}}
style={styles.upButtonImageStyle}
/>
</TouchableOpacity>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: StatusBar.currentHeight,
marginHorizontal: 16,
},
item: {
backgroundColor: "#f9c2ff",
padding: 20,
marginVertical: 8,
},
header: {
fontSize: 32,
backgroundColor: "#fff",
},
title: {
fontSize: 24,
},
upButtonStyle: {
position: "absolute",
width: 50,
height: 50,
alignItems: "center",
justifyContent: "center",
right: 30,
bottom: 70,
},
upButtonImageStyle: {
resizeMode: "contain",
width: 30,
height: 30,
},
downButtonStyle: {
position: "absolute",
width: 50,
height: 50,
alignItems: "center",
justifyContent: "center",
right: 30,
top: 70,
},
downButtonImageStyle: {
resizeMode: "contain",
width: 30,
height: 30,
},
});
export default App;
CodePudding user response:
When using refs the ref is an object , where the value you want to access is within the current property. Also, SectionList have the scrollToLoaction
method instead of the scrollToEnd because each section have items of their own.
Here's what I've put together. While the the buttons works on android and ios, on the web they wont position absolute nor will the buttons work:
import React from 'react';
import {
StyleSheet,
Text,
View,
SafeAreaView,
SectionList,
StatusBar,
TouchableOpacity,
Image,
useWindowDimensions,
} from 'react-native';
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const TouchableButton = ({ style, onPress, imgSrc }) => {
return (
<TouchableOpacity activeOpacity={0.5} onPress={onPress} style={style}>
<Image
source={{
uri: imgSrc,
}}
style={styles.downButtonImageStyle}
/>
</TouchableOpacity>
);
};
// made list longer
const DATA = [
{
title: 'Main dishes',
data: ['Pizza', 'Burger', 'Risotto', 'Steak', 'Spaghetti'],
},
{
title: 'Sides',
data: ['French Fries', 'Onion Rings', 'Fried Shrimps', 'Mac and Cheese'],
},
{
title: 'Drinks',
data: ['Water', 'Coke', 'Beer', 'Lemonade'],
},
{
title: 'Desserts',
data: ['Cheese Cake', 'Ice Cream', 'Chocolate Cake'],
},
];
const imgSize = 36;
const App = () => {
const listRef = React.useRef(null);
const [contentVerticalOffset, setContentVerticalOffset] = React.useState(0);
// use view layout to position the buttons absolutely
const [viewLayout, setViewLayout] = React.useState({});
const CONTENT_OFFSET_THRESHOLD = 300;
const upButtonHandler = () => {
//OnCLick of Up button we scrolled the list to top
console.log(`Scrolling to section:0 and index:0`);
if (!listRef.current.scrollToLocation) console.log('no scrollToLocation');
listRef.current.scrollToLocation?.({
itemIndex: 0,
sectionIndex: 0,
animated: true,
});
};
const downButtonHandler = () => {
//OnCLick of down button we scrolled the list to bottom
const sectionIndex = DATA.length - 1;
const itemIndex = DATA[sectionIndex].data.length - 1;
console.log(`Scrolling to section:${sectionIndex} and index:${itemIndex}`);
if (!listRef.current.scrollToLocation) console.log('no scrollToLocation');
listRef.current.scrollToLocation?.({
itemIndex,
sectionIndex,
animated: true,
});
};
return (
<SafeAreaView
style={styles.container}
onLayout={(e) => setViewLayout(e.nativeEvent.layout)}>
<TouchableButton
onPress={downButtonHandler}
style={{
position: 'absolute',
zIndex: 2,
left: viewLayout.width - viewLayout.x - imgSize,
top: viewLayout.y (StatusBar.currentHeight || 40),
}}
imgSrc="https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_down.png"
/>
<TouchableButton
onPress={upButtonHandler}
style={{
position: 'absolute',
zIndex: 2,
left: viewLayout.width - viewLayout.x - imgSize,
top: viewLayout.height - 20 - imgSize,
}}
imgSrc="https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_up.png"
/>
<SectionList
sections={DATA}
keyExtractor={(item, index) => item index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text style={styles.header}>{title}</Text>
)}
onScroll={(event) => {
setContentVerticalOffset(event.nativeEvent.contentOffset.y);
}}
ref={listRef}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight,
marginHorizontal: 16,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
},
header: {
fontSize: 32,
backgroundColor: '#fff',
},
title: {
fontSize: 24,
},
downButtonImageStyle: {
resizeMode: 'contain',
width: imgSize,
height: imgSize,
},
});
export default App;