I am building a portfolio site using nextjs + tailwindcss and framer motion for animations.
I have implemented a custom animated cursor using framer motion, this works fine but after a few minutes of reloading it keeps disappearing for no reason. Here is a video:
https://www.loom.com/share/84b2bbe766e14e938632b944578d4132
I am able to fix this issue by downgrading the framer-motion version to an older one (v5.3.2), but it has some other bugs with React v18, so I can't downgrade to that version.
I cannot figure out why this keeps disappearing and reappearing, and I can't reproduce this bug at will.
This is my custom mouse component:
<motion.div
variants={variants}
animate={cursorContext?.cursorVariant}
className={`h-5 w-5 rounded-full fixed top-[50vh] left-[50vw] pointer-events-
none z-[999] mix-blend-difference ${showCursor ? 'block' : 'hidden'}`}
/>
Here are my variants:
const variants = {
regular: {
x: cursorContext!.mousePosition.x - 5,
y: cursorContext!.mousePosition.y - 5,
border: "white 2px solid",
},
clickable: {
x: cursorContext!.mousePosition.x - 5,
y: cursorContext!.mousePosition.y - 5,
border: 'none',
backgroundColor: 'white',
width: 10,
height: 10,
},
largeClickable: {
x: cursorContext!.mousePosition.x - 10,
y: cursorContext!.mousePosition.y - 10,
border: 'none',
backgroundColor: 'white',
width: 20,
height: 20,
},
};
Here are all of my installed packages:
{
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "latest",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"#types/node": "18.11.3",
"#types/react": "18.0.21",
"#types/react-dom": "18.0.6",
"#types/react-scroll": "^1.8.5",
"autoprefixer": "^10.4.12",
"framer-motion": "^7.6.15",
"postcss": "^8.4.18",
"react-icons": "^4.6.0",
"react-scroll": "^1.8.8",
"tailwindcss": "^3.2.1",
"typescript": "4.8.4"
}
}
Thanks for the help in advance.
Related
I have a table as below and I am on #material-table/core: 0.2.52 version
<MaterialTable
isLoading={loading}
title=""
columns={[
{title: 'Track', field: 'track'},
{title: 'Tier', field: 'tier'},
{title: 'Architecture', field: 'architecture'},
{title: 'Archtier', field: 'archtier'},
{title: 'Lifecycle State', field: 'lifeCycleState'},
]}
data={data}
options={{
selection: true,
rowStyle: {
fontSize: '14px'
}
}}
localization={{
toolbar: {
nRowsSelected: '{0} application(s) selected'
},
body: {
emptyDataSourceMessage: `No applications found with owner email ${selectedEmail}`
}
}}
onSelectionChange={(rows) => onSelect(rows)}
/>
When I select all or individual row checkbox, I should see something like this below (Screenshot from using (https://github.com/mbrn/material-table)
But I am seeing nothing
am I missing any options here?
My dependencies in package.json
"dependencies": {
"#emotion/react": "^11.10.4",
"#emotion/styled": "^11.10.4",
"#material-table/core": "^0.2.52",
"#mui/icons-material": "^5.10.6",
"#mui/lab": "^5.0.0-alpha.100",
"#mui/material": "^5.10.6",
"axios": "^0.27.2",
"filefy": "^0.1.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-google-charts": "^4.0.0",
"react-router-dom": "^6.4.0",
"react-scripts": "^5.0.1",
"sass": "^1.54.9"
}
This has been reported and got fixed in v0.2.53
https://github.com/material-table-core/core/issues/660
I am trying to create a monorepo (yarn workspaces) with a next.js application and a separate react component library. But when i start the next.js app and try to use any component from the react library i get the error The keyword 'interface' is reserved.
My file structure:
/apps
/backend <- express server
/frontend <- next.js
/packages
/ui
index.tsx
/components
...
package.json
My package.json files:
/package.json
{
"name": "monorepo-demo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": "true",
"workspaces": [
"packages/**",
"apps/**"
],
"scripts": {
"dev:backend": "cd apps/backend && yarn dev",
"dev:frontend": "cd apps/frontend && yarn dev",
"dev": "concurrently \"yarn workspace frontend dev\" \"yarn workspace backend dev\""
},
"dependencies": {
"concurrently": "^7.4.0"
}
}
/apps/frontend/package.json
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"#types/styled-components": "^5.1.26",
"next": "12.3.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.4.0",
"styled-components": "^5.3.5",
"ui": "*"
},
"devDependencies": {
"#types/node": "18.7.16",
"#types/react": "18.0.18",
"#types/react-dom": "18.0.6",
"eslint": "8.23.0",
"eslint-config-next": "12.3.0",
"typescript": "4.8.3"
}
}
/packages/ui/package.json
{
"name": "ui",
"version": "0.0.0",
"private": true,
"license": "MIT",
"main": "dist/index.js",
"files": [
"components/**/*"
],
"dependencies": {
"#types/react": "^18.0.18",
"#types/styled-components": "^5.1.26",
"config": "*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^5.3.5",
"tsc": "^2.0.4",
"typescript": "^4.8.3"
},
"scripts": {
"build": "tsc",
"dev": "tsc -w"
}
}
Example of next.js page using components
/* /apps/frontend/pages/index.tsx */
import type { NextPage } from "next";
import { Button, Heading } from "ui";
import { BsEmojiSmile } from "react-icons/bs";
const Home: NextPage = () => {
return (
<>
<div>
<Button small>Small button</Button>
<Button medium>Medium button</Button>
<Button big>Big button</Button>
<Button>No size given (default to medium)</Button>
</div>
<div>
<Button small icon>
<BsEmojiSmile />
Small button w/icon
</Button>
<Button medium icon>
<BsEmojiSmile />
Medium button w/icon
</Button>
<Button big icon>
<BsEmojiSmile />
Big button w/icon
</Button>
<Button icon>
<BsEmojiSmile />
No size given (default to medium) w/icon
</Button>
</div>
<div>
<Heading small>Small heading (h3)</Heading>
<Heading medium>Medium heading (h2)</Heading>
<Heading big>Big heading (h1)</Heading>
</div>
</>
);
};
export default Home;
Example of component
/* /packages/ui/components/Button/Button.tsx */
import styled, { css } from "styled-components";
interface Props {
small?: boolean;
medium?: boolean;
big?: boolean;
icon?: boolean;
}
const Button = styled.button<Props>`
background: black;
border: none;
color: white;
border-radius: 7px;
cursor: pointer;
margin: 20px;
padding: ${(props) => {
if (props.small) return "8px 10px";
if (props.medium) return "12px 18px";
if (props.big) return "20px 25px";
return "12px 18px";
}};
font-size: ${(props) => {
if (props.small) return "12px";
if (props.medium) return "16px";
if (props.big) return "20px";
return "16px";
}};
// Alternative
${(props) =>
props.small &&
css`
padding: 8px 12px;
font-size: 12px;
`}
${(props) =>
props.icon &&
css`
display: inline-flex;
column-gap: 12px;
justify-content: center;
align-items: center;
svg,
i {
width: 24px;
height: 24px;
color: white;
}
`}
`;
export default Button;
I have tried just running yarn dev on the frontend project, yarn dev on both frontend and ui. But no luck. Also tried with and without tsc on ui package.
Anyone done something similar with any luck?
Thanks!
I recently added in a Lab component (Alert) and it seems like that component brings along with it some #material-ui/styles that conflict with the existing styles from the Core components. I get an error message about the duplicate styles.
I've looked at the documentation for the error message and tried the suggested remedies: npm dedupe, but no luck.
In the two images you can see that the existing styling (ex. the header color) changes while the Alert is being shown at the bottom, and goes away when the Alert is dismissed.
I understand the error is that the Alert requires specific styling to display green on success, red on error, etc. but I'm not sure how to combine that with the existing styling.
I am not using Webpack, this is a single application. I have not defined any custom material-ui styling.
Before alert - regular styling
During alert - confliction of styling
EDIT
package.json
{
"name": "Safety_Dashboard",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "cubejs-server"
},
"template": "docker",
"templateVersion": "0.27.53",
"devDependencies": {
"#cubejs-backend/postgres-driver": "^0.27.53",
"#cubejs-backend/server": "^0.27.53",
"#types/uuid": "^8.3.1",
"#typescript-eslint/parser": "^4.28.5",
"react-router-dom": "^5.3.0",
"typescript": "^4.3.5"
},
"dependencies": {
"#material-ui/core": "^4.12.2",
"#material-ui/data-grid": "^4.0.0-alpha.34",
"#material-ui/lab": "^4.0.0-alpha.60",
"#material-ui/pickers": "^3.3.10",
"#material-ui/x-grid-data-generator": "^4.0.0-alpha.34",
"#mui/icons-material": "^5.1.0",
"#nivo/core": "^0.73.0",
"#nivo/line": "^0.73.0",
"#visx/gradient": "^1.7.0",
"#visx/group": "^1.17.1",
"#visx/mock-data": "^1.7.0",
"#visx/react-spring": "^1.17.1",
"#visx/scale": "^1.14.0",
"#visx/shape": "^1.17.1",
"#visx/visx": "^1.18.1",
"codemirror": "^5.63.3",
"cytoscape-graphml": "^1.0.6",
"d3": "^7.0.0",
"js-convert-case": "^4.1.2",
"react-perfect-scrollbar": "^1.5.8",
"react-spring": "^9.2.4",
"xlsx": "^0.17.4"
}
}
package-lock.json (truncated)
"#material-ui/core": {
"version": "4.12.2",
"resolved": "https://registry.npmjs.org/#material-ui/core/-/core-4.12.2.tgz",
"integrity": "sha512-Q1npB8V73IC+eV2X6as+g71MpEGQwqKHUI2iujY62npk35V8nMx/bUXAHjv5kKG1BZ8s8XUWoG6s/VkjYPjjQA==",
"requires": {
"#babel/runtime": "^7.4.4",
"#material-ui/styles": "^4.11.4",
"#material-ui/system": "^4.12.1",
"#material-ui/types": "5.1.0",
"#material-ui/utils": "^4.11.2",
"#types/react-transition-group": "^4.2.0",
"clsx": "^1.0.4",
"hoist-non-react-statics": "^3.3.2",
"popper.js": "1.16.1-lts",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0",
"react-transition-group": "^4.4.0"
},
"dependencies": {
"#material-ui/utils": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/#material-ui/utils/-/utils-4.11.2.tgz",
"integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
"requires": {
"#babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0"
}
}
}
},
"#material-ui/lab": {
"version": "4.0.0-alpha.60",
"resolved": "https://registry.npmjs.org/#material-ui/lab/-/lab-4.0.0-alpha.60.tgz",
"integrity": "sha512-fadlYsPJF+0fx2lRuyqAuJj7hAS1tLDdIEEdov5jlrpb5pp4b+mRDUqQTUxi4inRZHS1bEXpU8QWUhO6xX88aA==",
"requires": {
"#babel/runtime": "^7.4.4",
"#material-ui/utils": "^4.11.2",
"clsx": "^1.0.4",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0"
},
"dependencies": {
"#material-ui/utils": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/#material-ui/utils/-/utils-4.11.2.tgz",
"integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
"requires": {
"#babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
"react-is": "^16.8.0 || ^17.0.0"
}
}
}
},
"#material-ui/styles": {
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/#material-ui/styles/-/styles-4.11.4.tgz",
"integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
"requires": {
"#babel/runtime": "^7.4.4",
"#emotion/hash": "^0.8.0",
"#material-ui/types": "5.1.0",
"#material-ui/utils": "^4.11.2",
"clsx": "^1.0.4",
"csstype": "^2.5.2",
"hoist-non-react-statics": "^3.3.2",
"jss": "^10.5.1",
"jss-plugin-camel-case": "^10.5.1",
"jss-plugin-default-unit": "^10.5.1",
"jss-plugin-global": "^10.5.1",
"jss-plugin-nested": "^10.5.1",
"jss-plugin-props-sort": "^10.5.1",
"jss-plugin-rule-value-function": "^10.5.1",
"jss-plugin-vendor-prefixer": "^10.5.1",
"prop-types": "^15.7.2"
},
EDIT 2
Note: The tool I'm working on is a prototype, so I went ahead and just built a workaround component for myself that copies the styles from the troublesome Alert component. Here's the code I used in case anybody in the future wants to do something similar.
PopupAlert.tsx
import React from 'react';
import { Paper, Snackbar, Typography } from '#material-ui/core';
// import Alert, { Color } from '#material-ui/lab/Alert';
import { Color } from '#material-ui/lab/Alert';
import styles from './PopupAlert.module.css';
import {
CheckCircleOutline,
ErrorOutline,
InfoOutlined,
WarningOutlined,
} from '#material-ui/icons';
import { Variant } from '#material-ui/core/styles/createTypography';
interface PopupAlertProps {
open: boolean,
message: string,
type: Color,
autoHideDuration?: number,
onClose?: () => void
}
const PopupAlert:React.FC<PopupAlertProps> = ({open, message, type, autoHideDuration=6000, onClose}) => {
const [myOpen, setMyOpen] = React.useState<boolean>(open);
React.useEffect(() => {
setMyOpen(open);
}, [open])
function handleOnClose() {
setMyOpen(false);
if(onClose) onClose()
}
// NOTE: As of writing this, the Alert material-ui component in the lab package conflicts with
// stylings from components in the core package. So, I went ahead and copied over the styles from
// the Alert component manually. If they fix this, this component can be pretty much simplified
// into the one-liner commented out at the bottom "<Alert severity={type} />"
// Relevant post: https://stackoverflow.com/questions/70628413/react-mui-styling-confliction-using-core-and-lab-components-in-same-app
const classes = [styles.paper];
type === "success" && classes.push(styles.successPaper);
type === "info" && classes.push(styles.infoPaper);
type === "warning" && classes.push(styles.warningPaper);
type === "error" && classes.push(styles.errorPaper);
const vertical = "top";
const horizontal = "center";
const typographVariant: Variant = "h6";
return (
<Snackbar
anchorOrigin={{ vertical, horizontal }}
open={myOpen}
onClose={handleOnClose}
autoHideDuration={autoHideDuration}
>
<>
{ type === "success" &&
<Paper className={classes.join(' ')} elevation={0}>
<div className={styles.iconWrapper}>
<CheckCircleOutline className={styles.successIcon} />
</div>
<div className={styles.errorMessage}>
<Typography variant={typographVariant}>{message}</Typography>
</div>
</Paper>
}
{ type === "info" &&
<Paper className={classes.join(' ')} elevation={0}>
<div className={styles.iconWrapper}>
<InfoOutlined className={styles.infoIcon} />
</div>
<div className={styles.errorMessage}>
<Typography variant={typographVariant}>{message}</Typography>
</div>
</Paper>
}
{ type === "warning" &&
<Paper className={classes.join(' ')} elevation={0}>
<div className={styles.iconWrapper}>
<WarningOutlined className={styles.warningIcon} />
</div>
<div className={styles.errorMessage}>
<Typography variant={typographVariant}>{message}</Typography>
</div>
</Paper>
}
{ type === "error" &&
<Paper className={classes.join(' ')} elevation={0}>
<div className={styles.iconWrapper}>
<ErrorOutline className={styles.errorIcon} />
</div>
<div className={styles.errorMessage}>
<Typography variant={typographVariant}>{message}</Typography>
</div>
</Paper>
}
{/* <Alert severity={type} /> */}
</>
</Snackbar>
)
}
export default PopupAlert
PopupAlert.module.css
.paper {
display: grid;
grid-template-columns: auto 1fr;
column-gap: 10px;
padding: 6px 16px;
}
.iconWrapper {
margin: auto 0;
}
.successPaper {
color: rgb(30, 70, 32) !important;
background-color: rgb(237, 247, 237) !important;
}
.successIcon {
color: #4caf50 !important;
}
.infoPaper {
color: rgb(13, 60, 97) !important;
background-color: rgb(232, 244, 253) !important;
}
.infoIcon {
color: #2196f3 !important;
}
.warningPaper {
color: rgb(102, 60, 0) !important;
background-color: rgb(255, 244, 229) !important;
}
.warningIcon {
color: #ff9800 !important;
}
.errorPaper {
color: rgb(97, 26, 21) !important;
background-color: rgb(253, 236, 234) !important;
}
.errorIcon {
color: #f44336 !important;
}
// In APP.js
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function Nave() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
----------------------------------------------------------
In package.json
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"#react-navigation/stack": "^5.2.14",
"expo": "~37.0.3",
"react": "~16.9.0",
"react-dom": "~16.9.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
"react-native-gesture-handler": "~1.6.0",
"react-native-web": "~0.11.7",
"react-navigation": "^4.3.8",
"react-native-safe-area-context": "0.7.3",
"react-native-reanimated": "~1.7.0",
"react-native-screens": "~2.2.0",
"#react-native-community/masked-view": "0.1.6"
},
"devDependencies": {
"babel-preset-expo": "~8.1.0",
"#babel/core": "^7.8.6"
},
"private": true
}
enter image description here
If I could get some help, it wouldn't be a denial.
I already did a complete re-installation via npm of react-native and react-navigation following the documentation.
But, I don't understand why my app doesn't launch and displays this error message. Knowing that I use an ios simulator on Macos catalina.
It looks like you don't have #react-navigation/native in your package.json. Did you follow the instructions in the react-navigation docs?
First run:
npm install #react-navigation/native
Then run:
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context #react-native-community/masked-view
Then you should be able to follow their Hello React Native tutorial.
I have a react app with Material-UI 1.2.
Although the state is properly updated, the drawer does not open close.
I have also correctly applied the bind on onLeftIconButtonTouchTap.
Here is my implementation of the TemporaryDrawer :
// .. imports
const styles = {
list: {
width: 250,
},
fullList: {
width: 'auto',
},
menuButton: {
marginLeft: 12,
marginRight: 36,
},
};
class TemporaryDrawer extends React.Component {
render() {
const { classes, toggleDrawer, isOpen } = this.props;
const sideList = (
<div className={classes.list}>
<List>
<ListItem button>
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText primary="Inbox" />
</ListItem>
</List>
</div>
);
console.log(' isOpen ' + isOpen);
return (
<div>
<IconButton className={classes.menuButton} color="inherit" onClick={toggleDrawer}>
<MenuIcon />
</IconButton>
<Drawer open={isOpen} onClose={toggleDrawer}>
<div
tabIndex={0}
role="button"
onClick={toggleDrawer}
onKeyDown={toggleDrawer}
>
{sideList}
</div>
</Drawer>
</div>
);
}
}
TemporaryDrawer.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(TemporaryDrawer);
used in this MenuAppBar.js
// ... imports
const styles = {
root: {
flexGrow: 1,
},
flex: {
flex: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
};
class MenuAppBar extends React.Component {
state = {
auth: true,
drawerOpen: false,
};
handleMenu = () => {
this.setState({ drawerOpen: !this.state.drawerOpen });
};
render() {
const { classes } = this.props;
const { drawerOpen } = this.state;
console.log(' state ' + this.state.drawerOpen);
return (
<div className={classes.root}>
<AppBar position="static" onLeftIconButtonTouchTap={this.handleMenu.bind(this)}>
<Toolbar>
<TemporaryDrawer isOpen={drawerOpen} toggleDrawer={this.handleMenu} />
</Toolbar>
</AppBar>
</div>
);
}
}
MenuAppBar.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(MenuAppBar);
package.json
{
"name": "find-swim",
"version": "0.1.0",
"private": true,
"dependencies": {
"#material-ui/codemod": "^1.1.0",
"#material-ui/core": "^1.2.0",
"#material-ui/icons": "^1.1.0",
"firebase": "^4.8.0",
"material-ui": "^0.19.4",
"material-ui-autocomplete-google-places": "^2.2.0",
"material-ui-places": "^1.1.7",
"mui-places-autocomplete": "^2.0.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-ga": "^2.4.1",
"react-google-button": "^0.4.0",
"react-google-maps": "^9.2.2",
"react-places-autocomplete": "^5.4.3",
"react-redux": "^5.0.6",
"react-redux-firebase": "^2.0.0-beta.16",
"react-redux-form": "^1.16.5",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-scripts": "^1.0.16",
"react-tap-event-plugin": "^3.0.2",
"recompose": "^0.26.0",
"redux": "^3.7.2",
"redux-devtools": "^3.4.0",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "set GENERATE_SOURCEMAP=false && react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"deploy": "firebase deploy"
},
"devDependencies": {
"redux-devtools-extension": "^2.13.2"
}
}
it s crazy but the issue was with the combination:
"#material-ui/core": "^1.2.0",
"react": "^16.0.0",
"react-dom": "^16.0.0",
As soon as I ve updated my dependencies to those of Ramil in his codesandbox, it worked.
"#material-ui/core": "1.2.3",
"react": "^16.3.0",
"react-dom": "^16.3.0",
I hope this helps someone..
I don't know where you got this onLeftIconButtonTouchTap={this.handleMenu.bind(this)}
But what you can do is:
<AppBar position="static">
<IconButton
className={classes.menuButton}
color="inherit"
aria-label="Menu"
onClick={this.handleMenu.bind(this)}
>
<MenuIcon />
</IconButton>
<Toolbar>
<TemporaryDrawer
isOpen={drawerOpen}
toggleDrawer={this.handleMenu}
/>
</Toolbar>
</AppBar>
Edit: I tried your code in sandbox. Apparently, nothing is wrong with your code. https://codesandbox.io/s/pk9921kkw0