Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

NotificationsTransition.tsx 2.4KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import React, { ReactElement, useEffect, useState } from 'react';
  2. export const NotificationsTransitionContext = React.createContext({
  3. unmounting: new Map<string, TimeoutType | null>()
  4. });
  5. type TimeoutType = ReturnType<typeof setTimeout>;
  6. const NotificationsTransition = ({ children }: { children: ReactElement[]; }) => {
  7. const [ childrenToRender, setChildrenToRender ] = useState(children);
  8. const [ timeoutIds, setTimeoutIds ] = useState(new Map<string, TimeoutType | null>());
  9. useEffect(() => {
  10. const toUnmount = childrenToRender.filter(child =>
  11. children.findIndex(c => c.props.uid === child.props.uid) === -1) ?? [];
  12. const toMount = children?.filter(child =>
  13. childrenToRender.findIndex(c => c.props.uid === child.props.uid) === -1) ?? [];
  14. /**
  15. * Update current notifications.
  16. * In some cases the UID is the same but the other props change.
  17. * This way we make sure the notification displays the latest info.
  18. */
  19. children.forEach(child => {
  20. const index = childrenToRender.findIndex(c => c.props.uid === child.props.uid);
  21. if (index !== -1) {
  22. childrenToRender[index] = child;
  23. }
  24. });
  25. if (toUnmount.length > 0) {
  26. const ids = new Map(timeoutIds);
  27. toUnmount.forEach(child => {
  28. const timeoutId = setTimeout(() => {
  29. timeoutIds.set(child.props.uid, null);
  30. setTimeoutIds(timeoutIds);
  31. }, 250);
  32. ids.set(child.props.uid, timeoutId);
  33. });
  34. setTimeoutIds(ids);
  35. }
  36. setChildrenToRender(toMount.concat(childrenToRender));
  37. }, [ children ]);
  38. useEffect(() => {
  39. const toRemove: string[] = [];
  40. timeoutIds.forEach((value, key) => {
  41. if (value === null) {
  42. toRemove.push(key);
  43. timeoutIds.delete(key);
  44. }
  45. });
  46. toRemove.length > 0 && setChildrenToRender(childrenToRender.filter(child =>
  47. toRemove.findIndex(id => child.props.uid === id) === -1));
  48. }, [ timeoutIds ]);
  49. return (
  50. <NotificationsTransitionContext.Provider value = {{ unmounting: timeoutIds }}>
  51. {childrenToRender}
  52. </NotificationsTransitionContext.Provider>
  53. );
  54. };
  55. export default NotificationsTransition;