React implements dynamic pop-up window component

React implements dynamic pop-up window component

When we write some UI components, if we don't consider the animation, it is very easy to achieve. The main thing is to switch the presence or absence (similar to the v-if attribute in Vue) or the visibility (similar to the v-show attribute in Vue).

1. Pop-ups without animation

In React, this can be achieved like this:

interface ModalProps {
  open: boolean;
  onClose?: () => void;
  children?: any;
}
const Modal = ({open.onClose, children}: ModalProps) => {
  if (!open) {
    return null;
  }
  return createPortal(<div>
    <div classname="modal-content">{children}</div>
    <div classname="modal-close-btn" onclick="{onClose}">x</div>
  </div>, document.body);
};

Directions:

const App = () => {
  const [open, setOpen] = useState(false);

  return (
    <div classname="app">
      <button onclick="{()" ==""> setOpen(true)}>show modal</button>
      <modal open="{open}" onclose="{()" ==""> setOpen(false)}>
        Modal content
      </modal>
    </div>
  );
};

Here we use the open attribute to control whether to display or not, but there is no gradient effect at all.

If we want to achieve animation effects such as fade and zoom, we need to modify this.

2. Create animated pop-ups yourself

When many students implement animation effects themselves, they often find that the animation works when it is displayed, but not when it is closed. It’s all because the timing of the animation was not controlled well. Here we first implement the flow of dynamic effects ourselves.

When I first started implementing it, the animation only had a start state and an end state, and it required a lot of variables and logic to control the animation.

Later, I referred to the implementation of react-transition-group component, which split the animation into several parts and controlled each part separately.

  1. The order of expansion animation: enter -> enter-active -> enter-done;
  2. The order of closing animation effects: exit -> exit-active -> exit-done;

The animation process is in the process of enter-active and exit-active .

We use a variable active to control whether the closing animation has been executed, and the parameter open only controls whether the expansion animation or the closing animation is executed.

The popup window is destroyed only when both open and active are false.

const Modal = ({ open, children, onClose }) => {
  const [active, setActive] = useState(false); // Pop-up window existence cycle if (!open && !active) {
    return null;
  }

  return ReactDOM.createPortal(
    <div classname="modal">
      <div classname="modal-content">{children}</div>
      <div classname="modal-close-btn" onclick="{onClose}">
        x
      </div>
    </div>,
    document.body,
  );
};

Here we continue to add changes in the animation process:

const [aniClassName, setAniClassName] = useState(''); // Animation class

// Transition execution completed listening function const onTransitionEnd = () => {
  // When open is rue, the end state is 'enter-done'
  // When open is not false, the end status is 'exit-done'
  setAniClassName(open ? 'enter-done' : 'exit-done');

  // If open is false, the pop-up window's life cycle ends when the animation ends if (!open) {
    setActive(false);
  }
};

useEffect(() => {
  if (open) {
    setActive(true);
    setAniClassName('enter');
    // setTimeout is used to switch classes and make transition happen setTimeout(() => {
      setAniClassName('enter-active');
    });
  } else {
    setAniClassName('exit');
    setTimeout(() => {
      setAniClassName('exit-active');
    });
  }
}, [open]);

The complete code of the Modal component is as follows:

const Modal = ({ open, children, onClose }) => {
  const [active, setActive] = useState(false); // Pop-up window existence cycle const [aniClassName, setAniClassName] = useState(''); // Animation class
  const onTransitionEnd = () => {
    setAniClassName(open ? 'enter-done' : 'exit-done');
    if (!open) {
      setActive(false);
    }
  };

  useEffect(() => {
    if (open) {
      setActive(true);
      setAniClassName('enter');
      setTimeout(() => {
        setAniClassName('enter-active');
      });
    } else {
      setAniClassName('exit');
      setTimeout(() => {
        setAniClassName('exit-active');
      });
    }
  }, [open]);

  if (!open && !active) {
    return null;
  }

  return ReactDOM.createPortal(
    <div classname="{'modal" '="" +="" aniclassname}="" ontransitionend="{onTransitionEnd}">
      <div classname="modal-content">{children}</div>
      <div classname="modal-close-btn" onclick="{onClose}">
        x
      </div>
    </div>,
    document.body,
  );
};

The flow process of the animation has been realized, and the style should also be written together. For example, we want to achieve a fade effect:

.enter {
  opacity: 0;
}
.enter-active {
  transition: opacity 200ms ease-in-out;
  opacity: 1;
}
.enter-done {
  opacity: 1;
}
.exit {
  opacity: 1;
}
.exit-active {
  opacity: 0;
  transition: opacity 200ms ease-in-out;
}
.exit-done {
  opacity: 0;
}

If you want to achieve the zoom effect, just modify these classes.

A pop-up window with animation has been implemented.

Directions:

const App = () => {
  const [open, setOpen] = useState(false);

  return (
    <div classname="app">
      <button onclick="{()" ==""> setOpen(true)}>show modal</button>
      <modal open="{open}" onclose="{()" ==""> setOpen(false)}>
        Modal content
      </modal>
    </div>
  );
};

Click the link to implement your own React pop-up window demo to see the effect.

Similarly, there are Toast and the like, which can also be implemented in this way.

3. react-transition-group

We borrowed the CSSTransition component in react-transition-group to achieve the dynamic effect. CSSTransition has encapsulated the process of dynamic expansion and closing for me. We can directly use this component when implementing pop-up windows.

There is an important property here: unmountOnExit , which means that the component will be uninstalled after the animation ends.

const Modal = ({ open, onClose }) => {
  // http://reactcommunity.org/react-transition-group/css-transition/
  // in property is true/false, true is to expand the animation, false is to close the animation return createPortal(
    <csstransition in="{open}" timeout="{200}" unmountonexit="">
      <div classname="modal">
        <div classname="modal-content">{children}</div>
        <div classname="modal-close-btn" onclick="{onClose}">
          x
        </div>
      </div>
    </csstransition>,
    document.body,
  );
};

After using the CSSTransition component, Modal's animation becomes much more convenient.

4. Conclusion

So far, the React Modal component to be animated has been implemented. Although there is no <transition> tag in React similar to the official definition of Vue, we can implement it ourselves or with the help of third-party components.

The above is the details of how to implement dynamic pop-up window components in React. For more information about React pop-up window components, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • React uses antd's upload component to implement the file form submission function (complete code)
  • Solution to React pure function component setState not refreshing the page update
  • Implementation of React star rating component
  • How to make React components full screen

<<:  Detailed explanation of Dockerfile to create a custom Docker image and comparison of CMD and ENTRYPOINT instructions

>>:  Explanation of the configuration and use of MySQL storage engine InnoDB

Recommend

Analysis of the solution to Nginx Session sharing problem

This article mainly introduces the solution to th...

A complete list of commonly used MySQL functions (classified and summarized)

1. Mathematical Functions ABS(x) returns the abso...

How to set up Referer in Nginx to prevent image theft

If the server's images are hotlinked by other...

Example analysis of the page splitting principle of MySQL clustered index

This article uses an example to illustrate the pa...

How to use not in to optimize MySql

Recently, when using select query in a project, I...

Install and configure MySQL under Linux

System: Ubuntu 16.04LTS 1\Download mysql-5.7.18-l...

Detailed explanation of how to use eslint in vue

Table of contents 1. Description 2. Download rela...

How does the MySQL database implement the XA specification?

MySQL consistency log What happens to uncommitted...

How to set up the use of Chinese input method in Ubuntu 18.04

In the latest version of Ubuntu, users no longer ...

Detailed explanation of count without filter conditions in MySQL

count(*) accomplish 1. MyISAM: Stores the total n...

Some conclusions on developing mobile websites

The mobile version of the website should at least...