KingSora / OverlayScrollbars

A javascript scrollbar plugin that hides the native scrollbars, provides custom styleable overlay scrollbars, and preserves the native functionality and feel.
https://kingsora.github.io/OverlayScrollbars
MIT License
3.78k stars 214 forks source link

Inline styles of child elements are reset if set during initialization of overlayscrollbar #561

Closed SethReloaded closed 11 months ago

SethReloaded commented 11 months ago

Describe the bug I am having an issue with the newest Version (0.5.2) of overlayscrollbars-react. It seems that manually set inlinestyles of child components get lost if changed during the initialization phase of the scrollbar. Setting defer={false} doesn't help.

To Reproduce

  1. Go to https://stackblitz.com/edit/overlayscrollbars-react-mv2rdw?file=src%2FApp.tsx%3AL39 (forked from the react example)
  2. On initial render, The added div myDiv has an opacity of 0 set.
  3. Then, in a useEffect, the opacity is set to 1. When the scrollbar mounts, the elements style is then reset to opacity 0.
  4. If you add a breakpoint to the useEffect hook where i set the opacity, and then reload the page, you can see that the style is first set, but removed when the simplebar is mounted.

Expected behavior Inline styles should remain on the element.

Examples See above (https://stackblitz.com/edit/overlayscrollbars-react-mv2rdw?file=src%2FApp.tsx%3AL39)

Environment The environment doesn't seem to make any difference. (Windows 10 / Chrome 116.0.5845.188)

Additional context Before the update to 0.5.2 (in 0.5.1), this did work as i expected it to. I'm not sure how to achieve the same behaviour now, after the update.

We are using the gsap library to animate inline styles. Elements are mounted with opacity 0 inside an OverlayScrollbarComponent, and then change the opacity to 1 when they mount (in some cases). This behaviour is now broken with the newest update (they stay at opacity 0).

Thank you in advance for looking into this. I am not even sure if this is a bug or just normal behaviour now with the defer api, any guidance in the right direction will be appreciated.

KingSora commented 11 months ago

@SethReloaded Good day :)

Is there any specific reason why you're not treating the style change as a state change? Something like:

const Component = () => {
  const [style, setStyle] = useState({ opacity: 0 });

  useEffect(() => {
    setStyle({ opacity: 1 }); 
  }, []);

  return <canvas style={style} />;
};

The reason this is happening is not strictly because of the plugin but because of how you are setting your side-effects

SethReloaded commented 11 months ago

Hey, thank you for your quick response! :)

The style is, in most cases, animated via inline styles. Therefore sometimes it is hard to track with react state. The lib we use for animation cannot update state afaik, therefore we are stuck with the inline styles.

In our case with 0.5.2, the content element is faded in partly, and when the simplebar is ready, reset to 0 opacity. In 0.5.1. the content element is faded in completely and not reset.

My React Components are nested like this:

function SomeComponent() {
  useEffect(() => {
    // fadein animation is triggered here, when SomeComponent is mounting, using the animatedElement ref
  }, []);

  return(
    <Wrapper>
      <OverlayScrollbarsComponent>
        <Content ref={animatedElement}/>
      </OverlayScrollbarsComponent>
    </Wrapper>
  )
}

We could try and track the initialized state of the scrollbar in the wrapper component and start the animation only, when the scrollbars are ready. If i understand the code correctly that should resolve our issue, is that correct?

However this solution would introduce a lot of up and down pushing of the initialized state through the components. We use a custom wrapper component for OverlayScrollbars to add some additional functionalities, which complicates things even more.

KingSora commented 11 months ago

Thats correct, you could use the components events for that instead of the useEffect:

<OverlayScrollbarsComponent 
  events={{ 
    initialized: () => {
      // fadein here
    }
  }}>
</OverlayScrollbarsComponent>
SethReloaded commented 11 months ago

Okay, thank you for the advice, i'll try that first, Thank you!

SethReloaded commented 11 months ago

Seems to work for me like this, thank your for the quick help!