Browse Source

Fix tooltip flashing react18, close #715 (#876)

* test: add reproducible demo story

* fix: tooltip flashing under react 18, close #715

* fix: add try catch, avoid error throw under react 16

* fix: tooltip flashing use animationFillMode instead of flushSync

* docs: update comment
pointhalo 3 years ago
parent
commit
7a6cc8ea6e

+ 5 - 0
content/start/changelog/index-en-US.md

@@ -16,6 +16,11 @@ Version:Major.Minor.Patch
 
 ---
 
+#### 🎉 2.12.0-beta.1 (2022-05-31)
+- 【Fix】
+    - Fix the problem that Tooltip, Popover, Select and other components with floating layers will flicker when they are used under React 1 [#715](https://github.com/DouyinFE/semi-design/issues/715)
+
+
 #### 🎉 2.12.0-beta.0 (2022-05-30)
 - 【Feat】
     - `Modal` adds A11y keyboard and focus adaptation.  [#205](https://github.com/DouyinFE/semi-design/issues/205)

+ 4 - 0
content/start/changelog/index.md

@@ -15,6 +15,10 @@ Semi 版本号遵循**Semver**规范(主版本号-次版本号-修订版本号
 
 ---
 
+#### 🎉 2.12.0-beta.1 (2022-05-31)
+- 【Fix】
+    - 修复 Tooltip、Popover、Select等带浮层组件,在 React 18 下使用,关闭时会闪烁的问题 [#715](https://github.com/DouyinFE/semi-design/issues/715)
+
 #### 🎉 2.12.0-beta.0 (2022-05-30)
 
 - 【Feat】

+ 2 - 1
packages/semi-ui/tooltip/TooltipStyledTransition.tsx

@@ -18,8 +18,9 @@ const TooltipTransition: React.FC<TooltipTransitionProps> = (props = {}) => {
     const { children } = props;
     const motion = getMotionObjFromProps(props);
 
+    //  add fillMode forward to fix issue 715, tooltip close will flashing under react 18
     return (
-        <StyledTransition {...props} enter={enterCls} leave={leaveCls} duration={'100ms'} {...motion}>
+        <StyledTransition {...props} enter={enterCls} leave={leaveCls} duration={'100ms'} {...motion} fillMode='forward'>
             {typeof children === 'function' ?
                 ({ animateCls, animateEvents, animateStyle }: any) => children({ animateCls, animateEvents, animateStyle }) :
                 children}

+ 90 - 0
packages/semi-ui/tooltip/_story/tooltip.stories.js

@@ -24,6 +24,7 @@ import ArrowPointAtCenter from './ArrowPointAtCenter';
 import CustomContainer from './CustomContainer';
 import ContainerPosition from './ContainerPosition';
 import { IconList, IconSidebar, IconEdit } from '@douyinfe/semi-icons';
+import TooltipTransition from '../TooltipStyledTransition';
 
 export default {
   title: 'Tooltip',
@@ -1007,3 +1008,92 @@ export const autoFocusContentDemo = () => {
     </div>
   );
 };
+
+
+export const FlashWithReact18 = () => {
+  const [visible, setV] = useState(false);
+
+  const change = () => {
+    setV(false);
+  }
+
+  return (<>
+    <Tooltip content='test work with react 18' position='bottom' trigger='custom' visible={visible}>
+      <Button style={{ marginLeft: 10 }} onClick={() => setV(true)}>show, semi with react 18 motion=true, abnormal</Button>
+    </Tooltip>
+    <Button style={{ marginLeft: 10 }} onClick={() => change()}>hide</Button>
+
+  </>);
+}
+
+
+
+
+export const Transition = () => {
+
+  const [transitionState, setT] = useState('');
+
+  const [insert, setInsert] = useState(false);
+
+  const handleLeave = () => {
+    console.log('set insert false')
+    setInsert(false);
+  }
+
+  const CommonDOM = () => {
+    const enterCls = `semi-tooltip-bounceIn`;
+    const leaveCls = `semi-tooltip-zoomOut`;
+    const animateStyle = {
+      animationDirection: 'normal',
+      animationName: transitionState === 'enter' ? enterCls : leaveCls,
+      animationDuration: '1000ms',
+    }
+
+    const handleEnd = () => {
+      if (transitionState === 'enter') {
+        console.log('animation end of show');
+      } else if (transitionState === 'leave') {
+        console.log('animation end of hide');
+        handleLeave();
+      }
+    }
+     
+    return <div style={{ ...animateStyle }} onAnimationEnd={handleEnd}>test</div>
+  };
+
+  const toggleShow = (insert) => {
+    if (!transitionState) {
+      setT('enter');
+      setInsert(insert);
+    } else if (transitionState === 'enter') {
+      setT('leave');
+    } else if (transitionState === 'leave') {
+      setT('enter');
+      setInsert(insert);
+    }
+  };
+
+  return (
+    <>
+      <div style={{ width: 200, height: 90, border: '1px solid var(--semi-color-text-1)' }}>
+        {
+          insert ? (
+            <CommonDOM></CommonDOM>
+            ): null
+        }
+      </div>
+      <Button onClick={() => toggleShow(true)}>show</Button>
+      <Button onClick={() => toggleShow(false)}>hide</Button>
+    </>
+  )
+}
+
+export const TransitionDemo = () => {
+  const [key, setKey] = useState(1);
+  return (
+    <>
+    <Transition key={key} />
+    <Button onClick={() => setKey(Math.random())}>reset Demo</Button>
+  </>
+  )
+}