How to declaratively animate a carousel

Ойын-сауық

In React, UI is a function of state. But when adding animations to a carousel, whether we slide left or right depends on if we pressed next or previous. How can we keep our code declarative but use information from previous renders to achieve the desired effect? Watch to find out!
🪄 Framer Motion course: samselikoff.com/framer-motion...
⚛️ What is Concurrent React? • React vocab explained:...
📖 Storing information from previous renders: beta.reactjs.org/apis/usestat...
🧑‍💻 Diff from the video: github.com/samselikoff/2022-0...
🚀 Live demo: bit.ly/3zhqRjm
- 0:00 - Intro
- 0:38 - Building the carousel
- 3:51 - Enter and exit animations
- 6:22 - How to store information from previous renders
- 14:00 - Refactoring to Variants so exiting elements get the latest value
- 19:22 - Dynamic width via useMeasure
- 20:52 - Extracting a usePrevious hook
- 22:14 - Outro

Пікірлер: 65

  • @samselikoff
    @samselikoff2 жыл бұрын

    👋 Hey all, hope you enjoyed the video! It didn't occur to me until I was publishing it that our move from calling setPrev() in the onClick handlers of each button, to using what ultimately became our usePrevious() hook, was actually a move from more imperative code to more declarative code. It's not just that the hook composes better with other components we may write in the future; it's that we're no longer thinking of _how_ the count state changes, but rather declaring all the state our component needs to render (both the UI and the animation), so that it is robust to state changes in the future. We've gone from caring _how_ the state changes (via a click), to not caring about how the state changes at all. So we're back to UI as a function of state. Imagine we make this component reusable, and now we accept `count` as a prop. In the onClick version, we'd need to update our component to also respond to change in the count prop. But with our usePrevious version, no matter how `count` changes (via a new prop, or another button we add to our code, or by adding a gesture where we can also swipe to increase count), our animation will work correctly. This is what made React so useful in the first place: turning imperative code like onClick={ $(.panel).slideDown() } into declarative code like . Declarative code helps us write more robust applications and is why I ultimately chose the title of the video that I did.

  • @webhelp4574

    @webhelp4574

    2 жыл бұрын

    Thank you Sam... helped a lot.

  • @ogpuzzle4382
    @ogpuzzle43822 жыл бұрын

    Not everybody is a great teacher, you definitely have a talent in clearly explaining complex topics in an easy to understand manner. It would be cool to see this carousel taken a step further and built into a onboarding UI with 3 screens, indicators and a couple of buttons, possibly done in the same style as your twitter clone or fitness app. I would imagine others would find that video pretty helpful.

  • @SamedGaming

    @SamedGaming

    2 жыл бұрын

    I agree, that would be an amazing tutorial to see

  • @JokersLaught
    @JokersLaught2 жыл бұрын

    I love your style when you first show the issues and the solution afterwards. That way we can learn much more than by just showing the solution straight away. Thanks :)

  • @gonzalowilliams
    @gonzalowilliams10 ай бұрын

    There is always something to learn from your videos.

  • @mryechkin
    @mryechkin2 жыл бұрын

    Dude, the timing of this is incredible! Literally was just looking at building a carousel with Framer Motion earlier this morning - so glad I saw this :)

  • @glen_hayes
    @glen_hayes2 жыл бұрын

    Amazing as always, thank you so much. High quality content.

  • @sergioccarneiro
    @sergioccarneiro2 жыл бұрын

    You always go the extra mile, I love it! 👏

  • @avidworkslol
    @avidworkslol2 жыл бұрын

    Your videos are all so helpful. Truly a master at explaining things in a digestible way.

  • @justine_chang39
    @justine_chang39 Жыл бұрын

    ABSOLUTELY AWESOME

  • @Rico-cp4xp
    @Rico-cp4xp2 жыл бұрын

    Love the way you explained this. Great work 👍

  • @EvertJunior
    @EvertJunior2 жыл бұрын

    Thank you for this video! I love framer motion, tailwind and React, web development is such a joy right now! Also, the hooks you used, including the previous state are in the awesome "react-use" library.

  • @andresgutgon
    @andresgutgon2 жыл бұрын

    "No effects, no refs" that could be a cool t-shirt

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    "No effect, no refs - just state" Love it!!

  • @shift-happens
    @shift-happens2 жыл бұрын

    What a time to be alive :D Sending love from Mexico

  • @roysheppard-dev
    @roysheppard-dev2 жыл бұрын

    Fantastic tutorial. Thanks for introducing me to useMeasure so many times in the past this would have saved me time

  • @mauroquiroga225
    @mauroquiroga2252 жыл бұрын

    Great explanation and amazing content! Thank you so much 😁

  • @webhelp4574
    @webhelp45742 жыл бұрын

    wow... this is so amazing... Never seen anyone teach react in such depth and with proper explanations... Thank you very much Sam 👍

  • @nikkoabucejo3886
    @nikkoabucejo38862 жыл бұрын

    How is this man only have 10k subs? You deserve more!! Thank you! great explanation.

  • @SonAyoD
    @SonAyoD Жыл бұрын

    Very nice!

  • @loquek
    @loquek2 жыл бұрын

    Love it, nice one

  • @fathulirfaan3917
    @fathulirfaan39177 ай бұрын

    always amazing

  • @raygan3
    @raygan32 жыл бұрын

    Great tutorial!

  • @diakitemohamed4629
    @diakitemohamed46292 жыл бұрын

    Thank you so much for this interesting video. You are the best teacher 😊

  • @raphauy
    @raphauy Жыл бұрын

    Thank you!

  • @forwardtrack
    @forwardtrack11 ай бұрын

    Great Great Job! Super Good!

  • @Chavez3d
    @Chavez3d2 жыл бұрын

    I learned a ton thanks 🙏

  • @ray-lee
    @ray-lee2 жыл бұрын

    love your videos! keep it coming😂

  • @awhmts
    @awhmts2 жыл бұрын

    so infomative thanks

  • @natiqmumtaz5309
    @natiqmumtaz53092 жыл бұрын

    the first thing I do is to like, amazing content

  • @abdelhadyshehab3844
    @abdelhadyshehab38442 жыл бұрын

    Good crack for me thank you

  • @dagoacarralero5080
    @dagoacarralero50806 ай бұрын

    Super nice one, i even learn a couple things about React, like the extra sauce of keys for mounting and un-mounting, just would prefer to keep intentions as words, for decreasing & increasing on the code. There are any alternatives to framer-motion to build such widgets?

  • @charliefoxtrot123
    @charliefoxtrot1232 жыл бұрын

    You should have way more subscribers than you do for the quality of your content. Hope your count goes up!

  • @JJ-ot3ps
    @JJ-ot3ps Жыл бұрын

    Hi Sam, great video! I am trying to learn the horizontal scroll like the one on amazon homepage where a lot of products are in one card container, is this the same as you showed on your video? thank you!

  • @ibukunokunfolami685
    @ibukunokunfolami6852 жыл бұрын

    When is the Framer motion class dropping !! Sam !!!!

  • @zindev
    @zindev2 жыл бұрын

    Hi, great explanation! How can I use Emmet like you did?

  • @mazwrld
    @mazwrld2 жыл бұрын

    I love how you're not a programmer first and story teller second

  • @kevinhe8188
    @kevinhe8188 Жыл бұрын

    really like your videos, although there are many developers are doing tutorial video, and I really feel connected with your, which really helpped me alot, thanks , but meanwhile i feel frustrated when i encounter bugs..

  • @alibek1545
    @alibek15452 жыл бұрын

    why don't we store `direction` and `count` in the same state? const [[count, direction], setSlider] = useState([null,1]) ... onClick={() => setSlider([count-1,-1])} // left ... onClick={() => setSlider([count+1,1])} // right or it is bad idea?

  • @alibek1545

    @alibek1545

    2 жыл бұрын

    also we can move all this logic to the custom hook const { count, direction, showNext, showPrev } = useSlider()

  • @samselikoff

    @samselikoff

    Жыл бұрын

    You could do that for sure but I wanted to show usePrevious because it's more composable. The onClick event handler doesn't have to know about the direction, you can derive the direction from previous and current. That being said I like the idea of a useSliderState() hook like you mentioned, so it's easier to use throughout your app!

  • @ronokoushique7434
    @ronokoushique7434 Жыл бұрын

    Is it required to generate the tuple state? I specified the direction as a state rather than a constant and modified it from inside the button press functions. The application is working perfectly.

  • @samselikoff

    @samselikoff

    Жыл бұрын

    Does your action set both the index and direction? That works for sure but the solution with the tuple is more composable since the event handler doesn't have to traffic that extra information 👍

  • @user-ud4zr4yr4v
    @user-ud4zr4yr4v Жыл бұрын

    Hello. Thank you for the video. I am currently implementing page (router) animation using framer-motion. I tried to implement it in a slide form, but I feel like it's been cut off because I can see the white margins after the page has been animationed to exit. Is there a way to implement page animation like carousel like the video above?

  • @tech3425
    @tech34252 жыл бұрын

    Couldn't you have just calculated the direction based on the chevron button that was clicked, directly inside of the motion div styling?

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    Just explained this a bit more in the pinned comment, but the shorter answer is: deriving the direction from changes to our `count` state makes our component more declarative and therefore more robust to changes in the future. Imagine we calculate the direction in onClick, but then someone comes along and adds the ability to swipe the carousel to change the count. We'd now need to update our previous code. And then someone makes our carousel reusable, and exposes the `count` as a prop. Now when the count changes from the outside, we'd again need to update our previous code for our animation to work. If we use the usePrevious hook we ended up with, and derive it solely from the count state, we no longer care _how_ the `count` changes, and our component is more declarative and robust to new ways of changing `count` in the future.

  • @tech3425

    @tech3425

    2 жыл бұрын

    @@samselikoff That's pretty neat

  • @electroheadfx
    @electroheadfx2 жыл бұрын

    amazing, how you may handle with images content ?

  • @wisdomeispower
    @wisdomeispower Жыл бұрын

    Why wont you get previous state from setState calback function? If you give setState callback function it will pass previous state to that callback function as an argument.

  • @Film14666
    @Film146662 жыл бұрын

    Thanks for the video, Sam ! I tried to subscribe to your Framer Motion course, but the sign up form doesn't work ...

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    I think it might be an ad blocker, could you disable and try again?

  • @Film14666

    @Film14666

    2 жыл бұрын

    ​@@samselikoff Yes, that was it - now it works !

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    @@Film14666 So glad to hear! Mind if I ask which ad blocker so we can test it out + maybe render some useful messaging?

  • @Troy-ol5fk
    @Troy-ol5fk2 жыл бұрын

    How to do page transition with framer motion ?

  • @bolatbekyeraliyev323
    @bolatbekyeraliyev3232 жыл бұрын

    @ 10:09 given that setPrev is placed AFTER setCount why does setPrev use existing value of the count and not the updated/incremented value?

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    Because `count` isn't updated until the next render. So during the current render, if you think about the code `setCount(count + 1) `, there's no way that code could possibly update the local `count` variable, based on the way JavaScript works. It's part of reason Hooks were designed the way they were. It can be a little confusing at first but it's good to wrap your mind around this because it helps you understand how React renders your app in frames over time. For a given render frame, a state variable will always be the same. The way to think about setState() is that it tells React to enqueue an entirely new render, with the updated state value. When React re-renders using the new value, it starts all over again from the top of your component.

  • @bolatbekyeraliyev323

    @bolatbekyeraliyev323

    2 жыл бұрын

    @@samselikoff I see. Thank you

  • @mohammedg485
    @mohammedg4852 жыл бұрын

    that's awesome. but why didn't you use useEffect with setTuple ?

  • @samselikoff

    @samselikoff

    2 жыл бұрын

    The trick in the docs (beta.reactjs.org/apis/usestate#storing-information-from-previous-renders) beats useEffect because (1) effects are just harder and more unpredictable, (2) effects run after render, so we would have a frame where `count` and `previous` were out of sync.

  • @sarimsarimsarim
    @sarimsarimsarim Жыл бұрын

    Hi Sam, thanks so much for this video. I tried to comment last night but it seems it was deleted, so apologies if there is a double-comment. I am trying to follow your example and have multiple items in each slide that stagger in. I faced the "wrong direction" issue like you did, which you fixed by setting custom on AnimatePresence. But that prevents me from setting custom on each child and passing the loop index so I can create a staggered exit. Would you know how to get around this problem? Tysm!

  • @samselikoff

    @samselikoff

    Жыл бұрын

    Any chance you could share a sandbox?

  • @nonefvnfvnjnjnjevjenjvonej3384
    @nonefvnfvnjnjnjevjenjvonej33842 жыл бұрын

    React is becoming one of the worst libraries ever. So much added complexity. Instead of empowering users it makes it so hard. Your video is great though.

  • @blazi_0

    @blazi_0

    Жыл бұрын

    its not about react its about the motion library itself

  • @greendsnow
    @greendsnow2 жыл бұрын

    React is broken.

Келесі