简体   繁体   中英

Animation resets states of child components

I have a framer motion component (I've tried with Stitches components too) that animates to and from view based on a useState variable:

const [visible, setVisible] = useState(true);

<motion.div
    animate={visible ? "one" : "two"}
    variants={{
      one: {
        transform: "translateX(0%)",
        opacity: 1
      },
      two: {
        transform: "translateX(100%)",
        opacity: 0
      }
    }}
  >
  // children
</motion.div>

The children components are wrapped in contexts, and the problem is that their states reset every time the animation is triggered.

I've tried declaring the animation component outside of its current scope. In its current scope it resets the states of everything except the "currentUser" state in my AuthProvider context. Outside the scope it resets "currentUser" too. I've decided not to include the original code for brevity.

Here is a minimum reproducible. If you type something in the input, and then click the toggle button, the input is lost.

DummyInputComponent should be stateless, use the value provided by the context and also have a onChange handler function passed on from the context

Something like this:

export function AuthProvider({ children }) {
  const [dummyValue, setDummyValue] = useState(null);

  const handlechange = (e) => {
    setDummyValue(e.target.value);
  };

  const value = {
    dummyValue,
    onChange: handlechange
  };

  const DummyInputComponent = () => {
    return <input value={value.dummyValue || ""} onChange={value.onChange} />;
  };

  return (
    <AuthContext.Provider value={value}>
      <DummyInputComponent />
    </AuthContext.Provider>
  );
}

Working CodeSandbox

I know the common use case for this is for performance tweaking, but I ended up avoiding the rerenders caused by framer motion (supposedly) by using memoization:

const Memoized = React.memo(({ children }) => {
  const [visible, setVisible] = useState(true);

 return (
  <motion.div
    animate={visible ? "one" : "two"}
    variants={{
      one: {
        transform: "translateX(0%)",
        opacity: 1
      },
      two: {
        transform: "translateX(100%)",
        opacity: 0
      }
    }}
  >
    {children}
  </motion.div>
 );
});

I don't know if this is a good way to do it, so I'll leave this open.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM