React-Spring 4 useSpring() methods, async/await springValue(), useSpring() [scriptsKeys], useLayout(), useSpring() onScroll()

The useSpring() animations run even without rendering, and api.start() can't change keyframes during a loop. We create a new useSpring() hook to change the style keyframe.

chevron-rightChanging useSpring() on the same loop elementhashtag

We useState() style the useSprings(), alternating them with useRef().

The new useSpring() won't start from:{} but from its already running keyframe.

//It will render depending on the number of keyframes and duration
//It renders on the DOM so we useState()

let [spin, api] = useSpring(()=>({
  from: {x: 0, y: 0, background: "lightblue"},
  to: [
    {x: 100, background: "lightblue"},
    {y: 80, background: "blue"},
    {x: 0, background: "lightgreen"},
    {y: 0, background: "green"},
  ],
  loop: true,
  config: config.wobbly
}))

let [spin1, api1] = useSpring(()=>({
  from: {x: 0, y: 0, background: "pink"},
  to: [
    {x: 100, background: "pink"},
    {y: 80, background: "orange"},
    {x: 0, background: "red"},
    {y: 0, background: "orange"},
  ],
  loop: true,
  config:{ duration: 1000 }
}))

let [stile, setStile] = useState(spin)
let trigger2 = useRef(false)

function cambio1(){

  trigger2.current ? setStile(spin) : setStile(spin1)
  trigger2.current = !trigger2.current
}

<div className="d-block">

  <animated.div className="boxo" style={stile}>
  </animated.div>

  <div className="text-center">
    <button className="btn btn-primary" onClick={cambio1}>Change</button>
  </div>

</div>

We can pause() and resume() to keep the useSpring() keyframe when changed.

chevron-rightChanging useSpring() while pause() resume() keyframeshashtag

We useEffect() to keep the second useSpring() paused before resuming and rendering it.

//useEffect() works once onLoad(), then we pause() resume() the useSpring()
let [spin2, api2] = useSpring(()=>({
  from: {x: 0, y: 0, background: "lightblue"},
  to: [
    {x: 100, background: "lightblue"},
    {y: 80, background: "blue"},
    {x: 0, background: "lightgreen"},
    {y: 0, background: "green"},
  ],
  loop: true,
  config: config.wobbly
}))

let [spin3, api3] = useSpring(()=>({
  from: {x: 0, y: 0, background: "pink"},
  to: [
    {x: 100, background: "pink"},
    {y: 80, background: "orange"},
    {x: 0, background: "red"},
    {y: 0, background: "orange"},
  ],
  loop: true,
  config:{ duration: 1000 }
}))

let [stile1, setStile1] = useState(spin2)
let trigger3 = useRef(false)

let fermo1 = true

useEffect(()=>{
  api3.pause()
}, [fermo1])

function cambio2(){

  if(trigger3.current){
    setStile1(spin2)
    api2.resume()
    api3.pause()      
  }else{
    setStile1(spin3)
    api3.resume()
    api2.pause()
  }

  trigger3.current = !trigger3.current
}

<div className="d-block">

  <animated.div className="boxo" style={stile1}>
  </animated.div>

  <button className="btn btn-primary" onClick={cambio2}>
    Resume
  </button>

</div>

Sequential New SpringValue() properties

We new SpringValue single style properties, to sequentially animate them as keyframes we async/await.

//We can keep multiple in an object and it's similar to useSpringValue()
import { SpringValue } from '@react-spring/web'

const mossa1 = {
  x: new SpringValue("0%", {config: {duration: 500} }),
  y: new SpringValue( 0, {config: {duration: 500}} ),
}

async function primo(){
  await mossa1.x.start("50%")
  await mossa1.y.start(100)

  mossa1.x.set("0%")
  mossa1.y.set(0)
  primo()
}

<div>
  <animated.div className="boxo" style={{ marginLeft: mossa1.x, y: mossa1.y }} >
  </animated.div>
</div>
chevron-rightSequential SpringValue objects on re-set loophashtag

We sequentially animate the SpringValue(), reset it to its starting value, and re-start its function.

new SpringValue()

Controller constructor and springValue

The new Controller class constructor sets an api imperative to springValues.

The each() method triggers once for each style property.

chevron-rightBounce controller animation with springValue() functionshashtag

No function triggers on bounce, we use an onChange() to trigger a limited number of horizontal animations, with a different timing function from the controller.

We reset() the controller springValues and start() with randomized tension/friction.

Bounce and horizontal animation

useSpring() scrips on conditional keyframes

We chain useSpring() keyframes with an array of spring objects, but we can't change the keyframe array during the animation (unless we change the rendered useSpring()). So we create a script.

An async function that await the next (function that returns a Promise on the spring state) once completed.

chevron-rightConditional keyframes and re-started loop animationshashtag

We useRef() to trigger a different set of keyframes in the script.

We reset the next keyframe with the ternary operator, making it transparent and positioning it at the beginning (from) using a different config() while restarting the loop with different keyframes.

The 2 useSpring() scrips being restarted and on loop.
chevron-rightCircle useSpring() animation on changing keyframes durationhashtag

We interpolate the useSpring() radians degree, we return the circular translate(x, y) style object to decostruct in the DOM.

We useState() switch between different useSpring() and classes, and we useRef() the keyframe script conditional for faster/slower config.

Switching multiple useSpring() on the same element

useIsomorphicLayoutEffect() and useReducedMotion()

The React hooks useEffect() and useLayout() affect the server and the client respectively.

We properly render useSpring() effects with useIsomorphicLayoutEffect(), using a useState() to dependency-animate useSpring() properties.

The useReducedMotion() hook will trigger if the user lowers animations in its device.

Animation useSpring() values onScroll()

The useScroll() is a utility abstraction used to create scroll-linked animations.

It returns the scrollY springValue, the pixel scroll distance, and scrollYProgress, a 0-1 value relative to the entire useRef() container. Both are built-in so we have to rename them with : if we have multiple useScroll().

We can animate an useSpring() on the useScroll() onChange() or interpolate it with a ternary operator.

useSpring() with interpolate or onChange() onScroll() animation
chevron-rightAnimated Math.cos() wave onScroll()hashtag

We loop a new Array().fill() to render multiple 100% viewpoint DOM elements, for the onScroll() to take place.

We interpolate the circle clipPath() area and onScroll() onChange() to animate the translateY(0-> 100%) text.

We Array.from() render fixed bands on both sides of the window, and we onScroll() scrollYProgress interpolate their width style prop.

Each bar will have a fixed scrollP (their current scroll position) and fixed percentileP (their singular index dependant percentage current position on the total height, 0.025 for the first and 1 for the last).

We use Math.cos() to start the wave at percentileP 0.025. We multiply the parameters' difference (onScroll() responsive) inside Math.cos() to increase the difference between bars and then the result by 40 (max-width)

The flex-column sidebar container is fixed, we changed the align-items for the left reverse bars.

Double inverted waves with useScroll() animation

Last updated