useScrollValue/useScrollState
malerba118 opened this issue · comments
Right now there's a few important things that scrollex can't handle and i think those are
Animating properties other than transform/opacity
Though it's not recommended for perf reasons, i'd like to provide a way to do it if the user wants to
Animating things based off scroll velocity (as opposed to scroll position)
Keyframes are controlled by scroll position so need a way to derive animations from velocity
Deriving react state from context values such as position, velocity, layout
If we could rerender a component say after the scroll position passes section.topAt('container-top') then we could fire off effects and tap into framer-motion animations through the animate prop.
So, the current plan to provide this missing features is to add two new hooks:
useScrollValue
This hook returns a framer-motion MotionValue, an observable value that can be updated outside of the react render loop, and passed to motion elements to animate them. The function passed to the hook will be re-executed any time that any of the context values change.
const rotate: MotionValue<number> = useScrollValue(({
position,
velocity,
section,
container,
maxScrollPosition
}: ScrollValueContext) => {
if (position < section.topAt('container-bottom')) {
return 0
}
// only takes effect when section is in view
return velocity / 50
})
<motion.div style={{ rotate }} />
useScrollState
This hook tracks the return value of the passed function as react state and will cause the host component to rerender any time that the return value changes. The return value will only be allowed to be a primitive (number, string, boolean, null, undefined) so that the old and new value can be compared using shallow equality. The function passed to the hook will be re-executed any time that any of the context values change.
const isSectionActive: boolean = useScrollState(({
position,
velocity,
section,
container,
maxScrollPosition
}: ScrollStateContext) => {
return position >= section.topAt('container-bottom') && position <= section.bottomAt('container-top'))
})
<motion.div animate={{ background: isSectionActive ? '#ff0000' : '#0000ff' }} />
implementation for these is pretty much ready:
https://github.com/malerba118/scrollex/tree/v2.0.0/src/hooks
i'm just waiting to add sufficient docs/examples before publishing v2 of scrollex