Framer Motion animation repeats on state change - reactjs

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();
}
}, [])

Related

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

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.

Update AppBar Title with only re-rending the AppBar

Objective
My goal is to have an AppBar at the top of the page that has a title in it. Then in the "Main" area of my screen I will have a route that renders a different component depending on the url. These are the components that need to update the page title that is being rendered in the AppBar. I only want the AppBar to re-render and nothing else, because it's the only thing that will have actual data change in.
Originally I was using useState() and just prop drilling the [pageTitle, setPageTitle] down to the components. From what I've read, you should avoid prop drilling if possible.
So I've tried leveraging useContext() but everything in the tree still re-renders.
Caveats
I would like to keep the layout of the HTML like I currently have it if possible. I'm not sure if that affects anything.
How I Tested For Re-rendering
I have console.log() statements per component. I got rid of strict mode in order to make sure the components are rendering only once. I tested this prior to leveraging useContext and the statements only print out once.
Now when I click on a navigation link you will notice it prints out a console.log() for all of the components that <PageTitleContext.Provider> is wrapping.
I only want the <AppBar> to re-render and nothing else, because this is the only component that is displaying the pageTitle.
Sandbox Code
https://codesandbox.io/s/appbar-page-title-update-m5y9el?file=/src/pages/Dashboard.jsx

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

history.push('/something') does push, but does not render the component because of exitBeforeEnter property of Animate Presence of framer-motion

I am trying to navigate to /main from postActions after deleting a post from PostDetail.
Code showing action
It pushes the /main but doesn't render the main component.
code showing where the problem occurs
However this does work if I am opting out exitBeforeEnter property of framer-motion on AnimatePresence.
Code showing partial solution by removing exitBeforeEnter
This causes animations for new component and exiting component at the same time.
Is there any way to use exitBeforeEnter and pushed component to render ?
Does your exiting component have an exit prop? AnimatePresence with enterBeforeExit will not render the new component if the previous one does not exit with an exit animation.

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
}, []);

Resources