formkit / auto-animate

A zero-config, drop-in animation utility that adds smooth transitions to your web app. You can use it with React, Vue, or any other JavaScript application.
https://auto-animate.formkit.com
MIT License
12.86k stars 226 forks source link

React: useAutoAnimate causes unnecessary renders #119

Closed drmercer closed 1 year ago

drmercer commented 1 year ago

Hi! 👋

Firstly, thanks for your work on this awesome project! 🙂 This is such a slick way to add animation with almost no effort!

I noticed that useAutoAnimate returns a new setEnabled function every time it's called. This causes unnecessary renders (and effect calls) if other hooks depend on that function.

I believe the solution is to use useCallback so that setEnabled is not re-created unless it has to be. I used patch-package to fix the issue locally - here is the diff that solved it for me:

diff --git a/node_modules/@formkit/auto-animate/react/index.mjs b/node_modules/@formkit/auto-animate/react/index.mjs
index 606d2da..387bf2a 100644
--- a/node_modules/@formkit/auto-animate/react/index.mjs
+++ b/node_modules/@formkit/auto-animate/react/index.mjs
@@ -1,4 +1,4 @@
-import { useRef, useState, useEffect } from 'react';
+import { useRef, useState, useEffect, useCallback } from 'react';
 import autoAnimate from '../index.mjs';

 /**
@@ -9,11 +9,11 @@ import autoAnimate from '../index.mjs';
 function useAutoAnimate(options) {
     const element = useRef(null);
     const [controller, setController] = useState();
-    const setEnabled = (enabled) => {
+    const setEnabled = useCallback((enabled) => {
         if (controller) {
             enabled ? controller.enable() : controller.disable();
         }
-    };
+    }, [controller]);
     useEffect(() => {
         if (element.current instanceof HTMLElement)
             setController(autoAnimate(element.current, options || {}));

This issue body was partially generated by patch-package.

justin-schroeder commented 1 year ago

I'll accept this if you want to provide it as a PR. Thanks!

limxingzhi commented 1 year ago

@justin-schroeder I made a PR for this couple of days ago, let me know how it goes 👍