I am looking for a best practice solution for the following (standard) Usecase:
I am having multiple screens (connected with react-navigation) with ScrollViews or Lists. Screens have sometimes same, sometimes different headers. These Headers include Animation depending on the scroll position of the Views. The Headers are sometimes mounted when creating the Navigator (parent View), sometimes they are modified within the view.
So my question is basically, how do I share a common scrollY-Variable like this
const scrollY = useRef(new Animated.Value(0)).current
with other components (especially if they are mounted in parent components, like the Header). Also how do I reset this variable if the View changes, or do I use an own instance of scrollY for every screen?
I would like to have a solution with hooks, such as:
const ParentComponent = props => (
<MainStack.Navigator
screenOptions={{
header: props => <Header {...props}/>
}}
>
<MainStack.Screen
name="Screen1"
component={Screen1}
/>
<MainStack.Screen
name="Screen2"
component={Screen2}
/>
</MainStack.Navigator>
)
// Similar to Screen2
const Screen1 = props => {
// get the global?! scrollY
const scrollY = useScrollY();
return(
<Animated.ScrollView
onScroll={
Animated.event(
[
{
nativeEvent: {contentOffset: {y: scrollY}}
}
]
)
}
>
</Animated.ScrollView>
);
}
// Header
const Header = props => {
// get the relevant scrollY variable from Screen1 or Screen2
const scrollY = useScrollY();
const animation = scrollY.interpolate({...})
return (...);
}
I had a working solution with putting scrollY to redux, but it seemed buggy & slow. Also, I tried to create a global scrollY in a file-scope (Note below) and made it accessible through a function. But that is not very React-like. Creating scrollY in the highest component and passing it down via props was also no real option, because the hierarchy is already too complex in reality. I would like to have a simple, performant, best-practice solution to share scrollY, preferrable with a hook. Any ideas?
Note: first Try with file-scope variable
let scrollY = new Animated.Value(0);
let history = {};
export const useScrollY = () => {
const reset = useCallback(
() => {
scrollY = new Animated.Value(0);
},
[]
);
return [scrollY, reset];
};
The problem here is that in a StackNavigator scenario, the parent stack will be reset to the animation of scroll position 0, although the scroll position might be still different. I also tried an approach with a history variable, but that did not really work.