Modal component renders Twice on open

I'm using react-spring to animate a Modal based on @reach/dialog. The Modal can have any children. In the children I'm fetching some data based on some prop.

The problem is that the fetch call is made two times on opening the modal. I think it has probably to do with how I'm managing the state and that is causing re-renders.

I'v tried memoizing the children inside the modal and it didn't work, so I think that the problem is outside of the Modal component.

Here is something close to my code and how it is working https://codesandbox.io/s/loving-liskov-1xouh

EDIT: I already know that if I remove the react-spring animation the double rendering doesn't happen, but I want to try keeping the animation intact.

Do you think you can help me to identify where is the bug? (Also some tips on good practice with hooks are highly appreciated).

Upvotes: 5

Views: 6109

Answers (3)

Peter Ambruzs
Peter Ambruzs

Reputation: 8223

The problem is, that at the end of the animation AnotherComponent remounts. I read similar problems about react-spring. One way could be, that you lift out the state from AnotherComponent to the index.js. This way the state will not lost at remount and you can prevent refetching the data.

const AnotherComponent = ({ url, todo, setTodo }) => {
  useEffect(() => {
    if (todo.length === 0) {
      axios.get(url).then(res => setTodo(res.data));
    }
  });
....
}

Here is my version: https://codesandbox.io/s/quiet-pond-idyee

Upvotes: 1

Srinivasan Raman
Srinivasan Raman

Reputation: 461

it renders three times because your return component has transitions.map since you have three item inside the

    from: { opacity: 0 }
    enter: { opacity: 1 }
    leave: { opacity: 0 }

the {children} was called two times when the isOpen is true you can fix the issue with just removing the from: { opacity: 0 } and leave: { opacity: 0 }

so change your modal.js => transitions

  const transitions = useTransition(isOpen, null, {    
    enter: { opacity: 1 }
  });

Upvotes: 1

kwdowik
kwdowik

Reputation: 56

I checked and it is rendered twice because of animation in a Modal component when an animation is finished, modal is rendered second time when I commented out fragment responsible for animation, Modal renders only once.

 const Modal = ({ children, toggle, isOpen }) => {
  // const transitions = useTransition(isOpen, null, {
  //   from: { opacity: 0 },
  //   enter: { opacity: 1 },
  //   leave: { opacity: 0 }
  // });
  console.log("render");
  const AnimatedDialogOverlay = animated(DialogOverlay);
  // return transitions.map(
  //   ({ item, key, props }) =>
  //     item && (
    return (
        <AnimatedDialogOverlay isOpen={isOpen}>
          <DialogContent>
            <div
              style={{
                display: `flex`,
                width: `100%`,
                alignItems: `center`,
                justifyContent: `space-between`
              }}
            >
              <h2 style={{ margin: `4px 0` }}>Modal Title</h2>
              <button onClick={toggle}>Close</button>
            </div>
            {children}
          </DialogContent>
        </AnimatedDialogOverlay>
    );
  //     )
  // );
};

Upvotes: 1

Related Questions