skip to Main Content

enter image description here

I wanted the button to move down to accomodate for a new row added. So I put layout on the MotionButton (Which is just a motion(...) wrapped component).

<div className="grid gap-5">
  <AnimatePresence>
    {flightDates.map((f, index) => (
      <motion.div
        key={index}
        exit={{
          opacity: 0,
          y: 10,
        }}
        initial={{
          opacity: 0,
          y: 10,
        }}
        animate={{
          opacity: 1,
          y: 0,
        }}
        transition={{
          duration: 0.2,
        }}
      >
        <FlightDateRow
          key={index}
          onChange={(updatedFlight) => {
            setFlightDates((prev) => {
              const newFlights = [...prev]
              newFlights[index] = {
                ...newFlights[index],
                ...updatedFlight,
              }
              return newFlights
            })
          }}
          onDelete={removeFlightDate(index)}
          canDelete={flightDates.length > 1}
          {...f}
        />
      </motion.div>
    ))}
  </AnimatePresence>
  <MotionButton
    className="w-min pl-2"
    variant="secondary"
    onClick={addNewFlightDate}
    layout
    transition={{
      duration: 0.2,
    }}
  >
    <PlusMini className="mr-2" />
    Flight
  </MotionButton>
</div>

2

Answers


  1. Chosen as BEST ANSWER

    I ended up having to wrap my button in a <motion.div layout></motion.div> instead of converting the button to a MotionButton. My button component would cause a remount to occur when clicking the button. So relying on an outer div to manage position within the layout fixed it.


  2. I’ve asked you in the comments if you could add the following debugging statement:

    useEffect(() => {
      console.log("button mounted");
      return () => console.log("button unmounted");
    }, []);
    

    Because I suspected you’re component was being re-mounted. This would explain the behaviour, since your button would trigger its unmount animation, and then its mount animation.

    You confirmed this was indeed the case:

    Yes it appears you’re right, my button is being re-mounted. When the button is clicked, the console prints out "button mounted" then "button unmounted" and then once again "button mounted".

    Since you haven’t provided much context in the question I can only guess why it’s being re-mounted. Here is a scenario that is probably the most common.


    Say though some sort of logic the structure of you output JSX changes from:

    <A>
      <YourButton />
    </A>
    

    to:

    <B>
      <YourButton />
    </B>
    

    This causes <A> to unmount, which in turn causes all the children of <A> also unmount. Then <B> is mounted with all its children. Due to the parent component change of YourButton, YourButton will also be unmounted and mounted.

    function Demo() {
      const [useA, setUseA] = React.useState(true);
      
      function toggleUseA(event) {
        event.preventDefault();
        setUseA(useA => !useA);
      }
      
      const Wrapper = useA ? A : B;
    
      return (
        <div>
          <button onClick={toggleUseA}>use {useA ? "B" : "A"}</button>
          <Wrapper><YourButton /></Wrapper>
        </div>
      );
    }
    
    const A = ({ children }) => <div>A{children}</div>;
    const B = ({ children }) => <div>B{children}</div>;
    
    function YourButton() {
      React.useEffect(() => {
        console.log("YourButton mounted");
        return () => console.log("YourButton unmounted");
      }, []);
      
      return null;
    }
    
    ReactDOM.createRoot(document.querySelector("#root")).render(<Demo />);
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <div id="root"></div>

    I don’t know if this is the exact cause, since there are other reasons why a component might re-mount. But this is in my opinion the most likely cause. It could be be the internals of Framer Motion it could be something else.

    I hope this helps your understanding of why this problem happens and are happy to see you already found a solution to your issue in your own answer.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search