malerba118 / scrollex

Build beautiful scroll experiences using minimal code

Home Page:https://scrollex-docs.vercel.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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