I'm working ona project management application , and I'm developing this feature where the project header can go into editing state where user can edit project title , this header has two child components HeaderContent and EditProjectForm :
>ProjectHeader
-->HeaderContent
-->EditProjectForm
my problem now is that when I fade out the HeaderContent
the faded In EditProjectForm
is intially pushed down then it jumps to its place , it seems that this happens because even though HeaderContent
was faded out it still was affecting the dom structure
here is a short screen recording I just uploaded to further make things clear https://www.youtube.com/watch?v=UerYDuEcUWQ
Header component
const ProjectHeader=()=>{
const [isEditingState, setisEditingProject] = useState({value:false,triggerFrom:"PANEL_HEADER"})
return <div>
<HeaderContent {...{isEditingProject, setisEditingProject}} />
<EditProjectForm {...{isEditingProject, setisEditingProject}} />
</div>
}
HeaderContent
const HeaderContent =({isEditingProject, setisEditingProject})=>{
const [render, setrender] = useState(true)
useEffect(() => {
let ref=null
// if(isEditingProject.triggerFrom =="EDIT_PROJECT_FORM") if I have don this whenever I change isEditingProject.value from this component this setTimeout below will be fired and I want to only be fired when this compoent is unmounted
if(isEditingProject.triggerFrom =="EDIT_PROJECT_FORM"){
ref= setTimeout(() => {
setrender(!isEditingProject.value)
}, 200);//wait until edit form finishes its fade_out animtion
}
return ()=>ref && clearTimeout(ref)
}, [isEditingProject])
return <AnimatePresence initial={false} >
{
render
&&(<motion.div
animate={{opacity:1 ,y:0}}
initial={{opacity:1 ,y:0}}
exit ={{opacity:0 ,y:10}}
transition={{
duration:.2,
opacity: { type: "spring", stiffness: 100 },
}}>
//.. header links and buttons and the title
<button onClick={e=>{
setrender(false)
setisEditingProject({...isEditingProject,value:true,triggerFrom:"PANEL_HEADER"})
}} >edit</button>
}
</AnimatePresence >
}
EditProjectForm
const EditProjectForm =({isEditingProject, setisEditingProject})=>{
const [render, setrender] = useState(true)
useEffect(() => {
let ref =null
// if(isEditingProject.triggerFrom =="PANEL_HEADER") if I haven't don this whenever I change isEditingProject.value from this component this setTimeout below will be fired and I want to only be fired when this compoent is unmounted
if(isEditingProject.triggerFrom =="PANEL_HEADER"){
ref=setTimeout(() => {
setrender(isEditingProject.value)
}, 200);
}
return ()=>ref && clearTimeout(ref)
}, [isEditingProject.value])
return <AnimatePresence>
{
render && <motion.form
animate={{ opacity:1 ,y:0 }}
initial={{ opacity:1 ,y:10 }}
exit ={{ opacity:0 ,y:-10}}
transition={{
duration:.2,
opacity: { type: "spring", stiffness: 100 },
}}
>
/.. title input
<button onClick={e=>{
setrender(false)
setisEditingProject({...isEditingProject,value:true,triggerFrom:"EDIT_PROJECT_FORM"})
}} >edit</button>
</motion.form>
}
</AnimatePresence>
}
It's problem with css, not with framer. My advise is to wrap your component with div absolute position, where top:0;
Maybe, you have some flex divs which trigger this "strange" behaviour