Reputation: 1305
I am having an issue (this is probably something I am ignoring within the render cycle) maintaining the position of two different scroll views when some of its child components are updated.
I have a hierarchy of views that is like:
<ScrollView vertical scrolling ability>
...
<ScrollView horizontal and vertical scrolling ability>
...
<Matrix>
<Cell updateCellStatusHandler={handler}>
</Matrix>
...
</ScrollView>
</ScrollView>
So, the updates on the internal cells, are resetting both scrolls on cell status update and this generates a super weird experience with the user having to scroll down/left/right back to continue interacting with the Matrix of cells with a status I have.
I have tried to save the scrollOffset (x,y) using useState
but if I change some cell, the state is reseted to (0,0) which is my initial state.
const [scrollOffset, setScrollOffset] = useState({
scrollX: 0,
scrollY: 0,
})
But without luck.
<ScrollView
{...props}
scrollEventThrottle={16}
ref={scrollReference}
// tslint:disable-next-line: jsx-no-lambda
onScroll={event => {
setScrollOffset({
scrollX: event.nativeEvent.contentOffset.x,
scrollY: event.nativeEvent.contentOffset.y,
})
}}
onScrollEndDrag={event => {
console.log(event.nativeEvent.contentOffset.y)
console.log(event.nativeEvent.contentOffset.x)
}}
>
{props.children}
</ScrollView>
One possible approach to solve this is to have a mechanism that allow me to save the scroll position before the update. But this will complicate a lot the communication between components, etc. By the way, the cell status update is being handled via Redux.
If some of you can bring you some light over this, would be great.
---- UPDATE 1 (Code of the panel component added) ----
Parent component is:
<View style={styles.container}>
<CustomScrollView enableResetScrollToCoords={false}>
<Section>
<WhiteContainer>
<View style={styles.rateContainer}>
<DescriptionTextStatus
statusText={getMessageForRate(availabilityRate)}
descriptionText={getDescriptionForRate(
availabilityRate,
isTeacher,
)}
icon={getImageForRate(availabilityRate)}
/>
</View>
</WhiteContainer>
</Section>
{!loggedUserIsTeacher() && <AvailabilityStart />}
<AvailabilityPanel />
<AvailabilityStatus />
<AvailabilityButtonSave />
</CustomScrollView>
</View>
Availability Panel is one of the childs
export const AvailabilityPanel: React.FunctionComponent<{}> = () => {
const panel: Cell[][] = useSelector((state: ReduxStore) => {
return get(state.entities, 'availability.panel', undefined)
})
if (panel === undefined) {
return <Nothing />
}
return (
<Section>
<WhiteContainer>
<LinearGradient
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
colors={[Palette.White, Palette.White68]}
>
<View style={styles.rateContainer}>
<DescriptionTextStatus
statusText={strings.warning}
descriptionText={strings.selectionMessage}
icon={'clock'}
/>
<View style={styles.separator} />
</View>
<View style={styles.container}>
<ScrollView
style={styles.scrollView}
directionalLockEnabled={false}
horizontal={true}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
>
<View style={styles.contentContainer}>
<View style={styles.weekdaysContainer}>
<PanelHeader weekdays={weekdays} />
</View>
<View style={styles.rowsContainer}>
{hours.map((hourLabel: string, index: number) => {
return (
<PanelRow
key={index}
hourLabel={hourLabel}
hoursRow={panel[index]}
rowIndex={index}
/>
)
})}
</View>
</View>
</ScrollView>
</View>
</LinearGradient>
</WhiteContainer>
</Section>
)
}
Thanks in advance.
Upvotes: 3
Views: 4411
Reputation: 4739
ScrollView does not reset scroll position because of child updates, regardless of whether you use Redux or not. You don't need to try to patch it with workarounds like saving current scroll positions. Rather just figure out what's wrong with your setup
It's hard to tell because you didn't provide your actual code, but I'm pretty sure one or both ScrollViews are remounted on updates (old ScrollView is removed and new one is created in its place with its own scroll position). It's likely that you are declaring new components inside render function so React will just remount them every time
Upvotes: 4
Reputation: 61
I think the overall idea of saving the scroll position of your scrollview is good.
I think the fact that your state is reset to 0 is probably due to Redux (not sure however, could you precise how your component is connected to redux ?). I am not so familiar with Hooks, but in a React Class component, I would try to save the scroll position in a non state property of the class. Maybe save it in a variable outside of your functional component ?
Then in the handler to manage cell updates, you could ensure that your scrollview scrolls to the position you saved (using ScrollView.scrollTo(), with {animated: false}
option so that the animation is not visible for the user)
Upvotes: 3