I've been using an outdated version of react-spring to animate a programmatic scroll.
The code used to be:
import { Spring } from "react-spring/renderprops";
// (...)
<Spring from={{ top: 0 }} to={{ top: LINE_HEIGHT * (page.from - 1) }}>
{(props) => (
<List
width={1}
height={LINE_HEIGHT * limit}
rowCount={sortedGauges.length}
rowHeight={LINE_HEIGHT}
rowRenderer={rowRenderer}
containerStyle={{
width: "100%",
maxWidth: "100%",
}}
style={{
width: "100%",
overflow: "hidden",
}}
scrollTop={props.top}
/>
)}
</Spring>
So the Spring component was updating a child with props.top each time the user clicked a button to get a smooth scroll. But I can't reproduce this result with the new useSpring API. What is the correct syntax?
Related
So, I have been trying to use Framer Motion for my React project. I basically want to animate the height from 0 to "auto", when the div gets rendered.
I tried the below code, but the height is not getting animated
<motion.div
initial={{ height: 0 }}
animate={{ height: "auto" }}
transition={{ duration: 0.5 }}
key={searchQuery?.length}
>
When I replaced height with width, the animation works fine, but can't figure out why the height is not getting animated. And I was unable to find any proper documentation regarding this.
Here is the CodeSandbox Link for demo.
Fixed versinn
What was wrong?
Your conditional rendering logic was in the wrong place, AnimatePresence works only if its direct child disappears.
exit prop was missing
key prop has to be stable, it can't be the length of the string
overflow: hidden have to be added so the children are invisible
Final code:
export default function App() {
const ref = useRef(null);
const [isActive, setIsActive] = useState(false);
const [searchQuery, setSearchQuery] = useState("");
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div>
<input
placeholder={"Enter Keyword"}
value={searchQuery}
onChange={(e) => {
setSearchQuery(e.target.value);
}}
/>
<AnimatePresence>
{searchQuery?.length >= 1 && (
<motion.div
style={{ overflow: "hidden" }}
initial={{ height: 0 }}
animate={{ height: "auto" }}
transition={{ duration: 0.5 }}
exit={{ height: 0 }}
key={"container"}
>
{dataList?.map((listItem) => (
<div
style={{
padding: "1rem",
color: "#E090EE",
borderBottom: "1px solid #E1E1E1",
}}
>
{listItem.activity_title}
</div>
))}
</motion.div>
)}
</AnimatePresence>
</div>
</div>
);
}
I'm building this app, and, as you can see, we have a left drawer and a main component in the right direction.
And when I close that drawer, the main component will move a little bit in order to occupy the rest of the space.
But, when there's too much data in the table, the animation is going to be super slow and it doesn't look nice.
This is the code, here, we have that left drawer and the main component
{/* Side panel */}
<LeftDrawer />
{/* Main content */}
<SinAsignarHero />
This is only the left drawer, that has an open prop that will receive a boolean from a redux reducer
<Drawer
sx={{
width: 260,
flexShrink: 0,
background: '#fafafa',
'& .MuiDrawer-paper': {
width: 260,
background: '#fafafa',
border: '0px',
boxShadow: '0px 8px 7px #0000003D',
boxSizing: 'border-box',
top: 'auto',
zIndex: 1,
},
}}
open={isOpen}
variant="persistent"
anchor="left"
>
{appOptions &&
appOptions.menus.map(({ id, nombre, sub_menu }) => {
return (
<Fragment key={id}>
<AppOptions nombre={nombre} sub_menu={sub_menu && sub_menu} />
</Fragment>
);
})}
</Drawer>
And the main component that will execute the animation to occupy the whole space with the same boolean from redux
const MainContent = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })<{
open?: boolean;
}>(({ theme, open }) => ({
background: '#fafafa',
height: '90.7vh',
overflowX: 'hidden',
flexGrow: 1,
padding: '40px 53px 0px 53px',
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
marginLeft: `-260px`,
...(open && {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginLeft: 0,
}),
}));
return (
<MainContent open={isDrawerOpen}>
<SinAsignarTitle setCount={setCount} setHasMore={setHasMore} />
<TableContainer component={Paper} sx={{ maxHeight: '73vh', borderRadius: '5px' }}>
{scrollData.length ? (
<>
<InfiniteScroll
dataLength={scrollData.length}
next={getMoreData}
hasMore={hasMore}
loader={<div></div>}
scrollableTarget="TableContainer"
>
<TableContainer
component={Paper}
sx={{ maxHeight: '73vh', borderRadius: '5px' }}
id="TableContainer"
>
<Table stickyHeader sx={{ minWidth: 800 }}>
{/* Table header */}
<SinAsignarHead setCount={setCount} setHasMore={setHasMore} />
{/* Hero content */}
<SinAsignarContent recogidas={scrollData} />
</Table>
</TableContainer>
</InfiniteScroll>
</>
) : (
<NotFound />
)}
</TableContainer>
</MainContent>
So, when there isn't that much data in the table, it is not that slow, but, I want the animation to be fast always.
This is pretty much what I would love to accomplish
https://mui.com/components/drawers/#persistent-drawer
If you go to the sandbox of that example, and you add too much text, the animation is still fine, I don't know if maybe there are too many things going on when there's too much data so it's harder for my left drawer and main component to make the animations as fast as possible. Is there something I can do in order to fix this ?¿
Try virtualized table.
Virtualization helps with performance issues.
https://mui.com/components/tables/#virtualized-table
I am trying to synchronize scrolling in my React page. As you can see, I have a div-container containing an arbitrary number of one Component, depending on the length of the array. I've tried react-scroll-sync and scroll-sync-react, but to no avail... Any ideas?
Edit: to be more precise, there is an iframe in each component that is the scrollable part.
<div>
{array.map((value, index) => (
<MyComponent style={{ overflow: 'auto' }} />
))}
</div>
I tried the following: Removing the Component and just producing arr.length-times iframes. But that also didn't work:
import "./styles.css";
// import { ScrollSync, ScrollSyncNode } from "scroll-sync-react";
import { ScrollSync, ScrollSyncPane } from "react-scroll-sync";
const arr = [1, 2, 3];
export default function App() {
return (
<ScrollSync>
<div
className="App"
style={{ display: "flex", height: "500px", width: "500px" }}
>
{arr.map((element, index) => (
<ScrollSyncPane key={arr[index]}>
<iframe
src={mySource}
key={arr[index]}
title={arr[index]}
styles={{ height: "300px", width: "200px", overflow: "auto" }}
/>
</ScrollSyncPane>
))}
</div>
</ScrollSync>
);
}
I have a fairly simple fade-in scenario, where I want to control the duration of the animation. But cannot wrap around my head around how to accomplish this.
Code excerpt:
function BoxA() {
return (
<Spring from={{ opacity: 0.2 }} to={{ opacity: 1 }}>
{props => (
<div
style={{
height: 100,
width: 100,
backgroundColor: "pink",
color: "#fff",
...props
}}
>
1
</div>
)}
</Spring>
);
}
Complete code example: https://codesandbox.io/s/n7pw660264
You have to set the config property for the duration.
<Spring config={{duration: 5000}} from={{ opacity: 0.2 }} to={{ opacity: 1 }}>
You can use delay property to control the animation,
According to documentation
Delay in ms before the animation starts (config.delay takes precedence
if present) */
like this
<Spring from={{ opacity: 0.2 }} delay={1000} to={{ opacity: 1 }}></Spring>
Demo
Source
I'm using a clipped under the app bar drawer with a canvas as the primary content. I have three collapsible cards in the drawer and when all set to be open by default, it shows a vertical scrollbar on the body and white space below the html element with the body element. If you close all three of the cards the scroll goes away. If you reopen the cards, the scroll doesn't appear. The issue only seems to occur when the page is loaded with all three cards open.
Our short term solution is to load the page with only two cards open, but I want to note even with two open, the drawer content extends below the window with no scroll. The CSS for the drawer shouldn't be the issue either. Anyone else experience this issue?
drawerPaper: {
position: 'relative',
width: 400,
overflowX: 'hidden',
overflowY: 'hidden',
'&:hover': {
overflowY: 'auto',
},
'&::-webkit-scrollbar': {
display: 'none',
},
},
<MuiThemeProvider theme={this.state.useDarkTheme ? darkTheme : lightTheme}>
<div className={classes.root}>
<AppBar position="absolute" className={classes.appBar}>
<Toolbar>
<div className={classes.flex}>
<Typography className={classes.headerTextColor} variant="title">
Title
</Typography>
{sealedBy}
</div>
<HeaderTools />
<Tooltip id="toggle-icon" title="Toggle light/dark theme">
<IconButton className={classes.headerTextColor} onClick={this.toggleTheme}>
<BrightnessMediumIcon />
</IconButton>
</Tooltip>
</Toolbar>
{spinner}
</AppBar>
<Drawer
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
>
<div className={classes.fixedWidth}>
<div className={classes.toolbar} />
<DocumentTools />
<SealingTools />
<AnnotationTools />
</div>
</Drawer>
<main className={classes.content}>
<div className={classes.toolbar} />
<DrawingCanvas />
</main>
</div>
</MuiThemeProvider>
You need to add height: 100% css property on some container components, and to styles to drawerPaper need add too.
I have setup here, its working, but probably depends on container components:
drawerPaper: {
width: 250,
overflow: "auto",
height: "100%",
[theme.breakpoints.up("md")]: {
overflow: "auto",
width: drawerWidth,
position: "relative",
height: "100%"
}
}