How to avoid a small delay in scrolling on react useEffect? - reactjs

I have a component that will automatically keep the scroll position when the child of the overflow: scroll parent is grows/shrinks.
The code that keeps the scroll position works fine. However because I use useEffect to readjust the scroll position. I noticed that there are some delay causing the scroll position to seem like a glitch (scrolled really fast down and back to the initial position).
So I thought that this is caused by react will render the component first and then execute the scrollTop in the useEffect.
Is there any way to avoid this delay?
Maybe this question can be simplified to:
How can I render a react component with initial scroll position? (without delay or useEffect?)

It sounds like you may need: useLayoutEffect, it fires immediately after the DOM has been updated, but before the browser has had a chance to paint those changes:
useLayoutEffect is a version of useEffect that fires before the
browser repaints the screen.
useEffect on the other hand runs after the browser has painted, so if you have some code inside the useEffect which results in DOM changes, you may notice some flicker because of that.

Related

Component using "Suspense" showing spinner on consequent loads (changing its height for a moment)

I'm rendering a number of items, where each individual item uses the same component:
This component internally uses Suspense:
<Suspense fallback={<Spinner />}>{children}</Suspense>
Whenever I click the paginator, a new set of items is rendered. Each of the items uses the same "Suspensed" component.
Problem: Each of the instances shows a fallback (spinner, loader) for a moment, and only then its content.
Since the fallback has constant height, this changes the height of the parent container, which makes the whole page jumping around:
I'm wondering how could I fix this? Basically, I'd like to avoid the new set of items to collapse due to showing the fallback. Sure, showing the fallback on initial load is fine, but I don't think the already loaded component (dynamically imported code) should show it on consequent pages.
I tried using React.startTransition, but that didn't help.
I also checked with components which are not lazily loaded, and everything works fine (parent height remains constant).
Thanks for help!
Update: I came up with a "poor man's fix":
wrapping children inside 2 divs
ResizeObserver monitoring the height of the inner div and setting the same height to the outer one, but in debounced fashion (100ms later)
Resources:
https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver
https://www.npmjs.com/package/use-debounce
Note: You'll probably need to mock ResizeObserver in your Jest tests: https://github.com/que-etc/resize-observer-polyfill/issues/50#issuecomment-488064120

Framer Motion animation repeats on state change

I am building a task manager with React and Framer Motion. I'm animating a slide in transition for a react Portal / modal. The portal has a form in it with multiple input text fields in it, each with their own onChange handlers. However, whenever the onChange handler is called, the animation replays itself. I'm not sure what is the issue.
I've tried to add a repeat value of 0 to the transitions, but there seems to be no change. I'm pretty new to framer motion, so please let me what other details I need to provide.
If you are using animate prop, the component will animate on each render, this is useful only for simple cases, where the component typically renders once on the page. But in your case, this prop will not work since the input field re-renders on each change.
For your use case, it's better to use useAnimation() hook and pass the animationControl as variant prop and fire it manually on the first render only.
useEffect(() => {
if (firstRender) {
animationControl.start();
}
}, [])

React - rerender after content becomes visible

I have a React (hooks) component inside an Accordion (<details> element).
The component makes some assumptions about offsetWidth for some child elements being available, but as the accordion is closed, the component is not visible and these Refs have an offsetWidth of 0.
I need to re-render the component, after the accordion is open and the component itself becomes visible.
I am trying passing the state of the accordion (open/closed) down to the component to trigger a render when this changes, but useEffect is run before the browser draws the component, so width is still 0 even if accordion state is open.
Any idea how to solve this?
Well actually useEffect is called after the component re-render. So that is probably not your problem.
I suggest using the state for dynamically adding a class with display: none and removing it. instead of changing its width to zero

Highcharts animation occurs every render

I am using react-highcharts (wrapper for highcharts)
and enabled animations for better user experience,
but the animation occurs in every render, as example:
https://media.giphy.com/media/JAQVpMKbeXh1Y9jAJ6/giphy.gif
Is there a way for making animations only once?
I'll be glad for any help
thanks
For a cleaner user-experience I would recommend using the animation only once on the first render of the component, hence, if you are using React hooks for example, use the useEffect hook, to apply the animation, but send an empty array as the second argument of useEffect so it will render the animation only once after the first render is triggered.
useEffect(() => {
// Apply animation
}, []);

Multiple re-renders breaks CSS transition

I have a draggable React pure component that pushes aside other draggables around it, triggering multiple re-renders.
However when the component is dragged too quickly (causing another re-render to occur before the CSS transition can finish animating) strange behaviours show up. The surrounding draggables will jump around unpredictably.
Everything works fine and transitions smoothly as long as I set a low enough transition time or drag the component slowly enough so that the transition finishes before the next re-render.
I'm using simple CSS transitions inside the component's style props, adding the transition property when the component is being actively dragged and removing it otherwise.
transition: "all 500ms ease"
Examples:
In both gifs, I'm dragging the leftmost panel towards the right. Each time there is a column swap, there is a re-render.
The top gif shows everything functioning as expected when dragging slowly and setting a low 100ms transition time.
In the bottom gif, I'm dragging too quickly causing the component to re-render before the first transition can complete. You can observe the leftmost panel moving out of frame towards the left side even though it's not being dragged.
Is there any way to delay re-rendering until the CSS animation is finished?
Is there another solution here that's typically applied for these situations?

Resources