ReactJs: Move data fetching code or side effects to componentDidUpdate - reactjs

I got following warning, but I do not know which data change it means, do you have any idea?
Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See react-unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at:
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.
Please update the following components: t
code:
import React, { Component } from "react";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import Button from "#material-ui/core/Button";
import FacebookLogin from "react-facebook-login";
import Menu from "#material-ui/core/Menu";
import MenuItem from "#material-ui/core/MenuItem";
// import this
import { withStyles } from "#material-ui/core/styles";
// make this
const styles = theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
});
class App extends Component {
state = {
accessToken: "",
isLoggedIn: false,
userID: "",
name: "",
email: "",
picture: ""
};
responseFacebook = response => {
this.setState({
accessToken: response.accessToken,
isLoggedIn: true,
userID: response.userID,
name: response.name,
email: response.email,
picture: response.picture.data.url
});
};
handleClick = event => this.setState({ anchorEl: event.currentTarget });
handleClose = () => {
this.setState({ anchorEl: undefined });
};
handleCloseAndLogOut = () => {
this.setState({ anchorEl: undefined });
this.setState({ isLoggedIn: undefined });
this.setState({ userID: undefined });
this.setState({ name: undefined });
this.setState({ email: undefined });
this.setState({ picture: undefined });
};
componentDidMount() {
document.title = "Tiket.hu";
}
componentDidUpdate() {
// What put here?
}
render() {
let fbContent;
let listContent;
//const { anchorEl } = this.state;
if (this.state.isLoggedIn) {
fbContent = (
<div>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={this.handleClick}
>
{this.state.name}
</Button>
<Menu
id="simple-menu"
anchorEl={this.status.anchorEl}
keepMounted
open={Boolean(this.status.anchorEl)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleCloseAndLogOut}>Log out</MenuItem>
<MenuItem onClick={this.handleClose}>
Switch mode to Release
</MenuItem>
<MenuItem onClick={this.handleClose}>My tickets</MenuItem>
</Menu>
</div>
);
} else {
let fbAppId;
if (
window.location.hostname === "localhost" ||
window.location.hostname === "127.0.0.1"
)
fbAppId = "402670860613108";
else fbAppId = "2526636684068727";
fbContent = (
<FacebookLogin
appId={fbAppId}
autoLoad={true}
fields="name,email,picture"
onClick={this.componentClicked}
callback={this.responseFacebook}
/>
);
}
return (
<div className="App">
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={this.props.classes.title}>
Tiket.hu
</Typography>
<Button color="inherit">Search</Button>
<Button color="inherit">Basket</Button>
{fbContent}
</Toolbar>
</AppBar>
{listContent}
</div>
);
}
}
export default withStyles(styles)(App);

The component you show doesn't have a componentWillReceiveProps, so it's not the problem. The error message includes this:
Please update the following components: t
So we're looking for a component named t. If you have one with that name, that's the one you'd need to fix. But my guess is that's not one of your components, but rather one that's being used indirectly by one of the libraries you've imported. If that's the case, only the library creator will be able to fix this, and you'd then import a new version of their code.
This warning will not stop your code from running with current versions of react, but it will prevent you from upgrading to version 17 of react (which doesn't exist yet)

Related

Error: out of memory when trying to run create-react-app

When I run npm start in chrome (create-react-app) it takes a while to load and then it crashes. the Error displays "out of memory". I cleared all my tabs and cache, and since other apps run just fine I have been able to tell the error is in the code. When I removed the Reserve_Button Component the application ran just fine. I think there may be some sort of memory leak related to SetState but I'm relatively new to React so there is not much more I can tell.
import React from "react";
import "./reserve_button.css";
// import Reserve_Form from "./Reserve_Form";
// import { connect } from "react-redux";
// import { submitreservation } from "../../Actions/index";
import Modal from "./modal";
class Button extends React.Component {
state = {
firstname: "",
Lastname: "",
};
showmodal = {
open: false,
};
// onSubmit = (formValues) => {
// this.props.submitreservation(formValues);
// };
showModal() {
if (this.state.open) {
return (
<Modal
open={this.state.open}
onDismiss={() => this.setState({ open: false })}
title="Modal Title"
content="Modal Body"
actions={<div className="ui button">Button</div>}
/>
);
}
}
render() {
return (
<div className="body">
<Button
onClick={() => this.setState({ open: !this.state.open })}
className="neon-button"
>
Reserve session
</Button>
{this.showModal()}
</div>
);
}
}
// <Reserve_Form onSubmit={this.onSubmit} />;
// export default connect(null, { submitreservation })(Button);
export default Button;
this is the Modal:
import React from "react";
import ReactDOM from "react-dom";
const Modal = (props) => {
return ReactDOM.createPortal(
<div onClick={props.onDismiss}>
<div onClick={(e) => e.stopPropagation()}>
<i onClick={props.onDismiss}></i>
<div className="header">{props.title}</div>
<div className="content">{props.content}</div>
<div className="actions">{props.actions}</div>
</div>
</div>,
document.querySelector("section")
);
};
export default Modal;
there are no set class names in a CSS file for the modal but I don't think that CSS would be the source of the problem.
UPDATE: when I console log this.state.open it prints "false" like 1000 times a second
There is an optimization you can make to your code. Perhaps it will help fix the error:
Instead of
<Button
onClick={() => this.setState({ open: !this.state.open })}
className="neon-button"
>
when relying on the previous state of a react component use the previous state to update the value. It looks something like this:
<Button
onClick={() => this.setState((prevState) => { open: !prevState.open })}
className="neon-button"
>
By doing this, we are referencing the previous state of this.state.open. This is particularly important as not all state updates happen instantaneously and so there is a possibility of referencing an older value of this.state.open in your approach.

Snackbar can't give width and handleClose

I can't give 100% width on the snackbar and I also have a snackbarClose method but I can't implement it on the snackbar. I also want a button 'X' which button will perform the snackbarClose method.
CodeSandbox : https://codesandbox.io/s/xenodochial-kapitsa-f5yd7?file=/src/Demo.js:693-706
import React, { Component } from "react";
import { Container, Grid, Button, Snackbar } from "#material-ui/core";
import MuiAlert from "#material-ui/lab/Alert";
import { withStyles } from "#material-ui/core/styles";
const styles = (theme) => ({});
function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
class Demo extends Component {
constructor() {
super();
this.state = {
snackbaropen: false,
snackbarmsg: "",
severity: ""
};
this.onClick = this.onClick.bind(this);
}
onClick = (event) => {
this.setState({
snackbaropen: true,
snackbarmsg: "Data Saved",
severity: "success"
});
};
snackbarClose = (event) => {
this.setState({ snackbaropen: false });
};
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Container>
<Grid container spacing={2}>
<Grid item xs={12} sm={6} md={6} lg={6} xl={6}>
<Button
variant="contained"
color="primary"
onClick={this.onClick}
>
Submit
</Button>
<Snackbar
open={this.state.snackbaropen}
autoHideDuration={3000}
onClose={this.snackbarClose}
>
<Alert severity={this.state.severity}>
{this.state.snackbarmsg}
</Alert>
</Snackbar>
</Grid>
</Grid>
</Container>
</React.Fragment>
);
}
}
export default withStyles(styles, { withTheme: true })(Demo);
If you want 100% width on snackbar, you need to specify width for Alert and Snackbar component and for close button you need to specify onClose function on Alert component.
<Snackbar
open={this.state.snackbaropen}
autoHideDuration={3000}
onClose={this.snackbarClose}
style={{ width: "100%" }} // specify width 100%
>
<Alert
onClose={this.snackbarClose} // specify onClose method
severity={this.state.severity}
style={{ width: "100%" }} // specify width 100%
>
{this.state.snackbarmsg}
</Alert>
</Snackbar>
For snackback closing on outside click, you need to change close function like below:-
snackbarClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
this.setState({ snackbaropen: false });
};
Demo: https://codesandbox.io/s/heuristic-khayyam-xo464
This is so complicated to solve problem.
What React version used?
If you used React(over 16.8), I recommend solution I used.
Use React.createContext, React.useContext
Use React.useReducer
Make custom Hook like useSnackBar
Mount SnackBarProvider on the App
import React from 'react';
import ToastContext, { ToastProps } from './ToastContext';
const useToast = () => {
const [, dispatch] = React.useContext(ToastContext);
const message = (toast: ToastProps) => {
dispatch({
type: 'ADD_TOAST',
payload: toast,
});
};
return message;
};
export { useToast };
export default useToast;
const ToastProvider: React.FC<ToastProviderProps> = ({
children,
placement = 'top-right',
timeout = 5000,
}) => {
const [toasts, dispatch] = React.useReducer(toastReducer, []);
return (
<ToastContext.Provider value={[toasts, dispatch]}>
<ToastProviderWrapper>
<ToastProviderContainer className={classnames(placement)}>
{toasts.map((toast, index) => (
<ToastCard {...toast} key={index} timeout={timeout} />
))}
</ToastProviderContainer>
</ToastProviderWrapper>
{children}
</ToastContext.Provider>
);
};
const Index = () => (
<ToastProvider>
<App />
</ToastProvider>
);
const rootElement = document.getElementById('root');
ReactDOM.render(<Index />, rootElement);
You can give data through dispatch(action), reducers
You can Dispatch event all the pages.
These Doms were rendered Root Element like React.Portal. then you can edit global position styles as system.
The SnackBar component delegates to or inherits its style or appearance from its children component, so you can instead adjust the width of the Alert component inside the SnackBar.
<Alert style={{ width: "100%" }} severity={this.state.severity}>
{this.state.snackbarmsg}
</Alert>
This should also adjust the width of the SnackBar component and make it fullwidth.

Why 'Invalid Hook Call Warning' for Material-UI and Facebook Login example for React?

What is wrong in this code? I put it together from a material-ui example and facebook login button react example.
import React, { Component } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/core/Menu';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import FacebookLogin from 'react-facebook-login';
export default class Demo extends Component {
useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}));
classes = this.useStyles();
handleClick = event => this.setState({ anchorEl: event.currentTarget })
handleClose = () => this.setState({ anchorEl: null })
state = {
isLoggedIn: false,
userID: '',
name: '',
email: '',
piture: '',
anchorEl: null,
setAnchorEl: null
};
componentClicked = () => {
console.log("componentClicked");
};
responseFacebook = (response) => {
console.log(response);
this.setState({
isLoggedIn: true,
userID: response.userID,
name: response.name,
email: response.email,
picture: response.picture
});
console.log(response);
};
render() {
let fbContent;
if (this.state.isLoggedIn) {
fbContent = "hello"; //this.state.name;
} else {
fbContent = (<FacebookLogin appId="2526636684068727"
autoLoad={true}
fields="name,email,picture"
onClick={this.componentClicked}
callback={this.responseFacebook}
cssClass="my-facebook-button-class"/>);
}
return (
<div>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={this.classes.title}>
Tiket.hu
</Typography>
<Button color="inherit">Search</Button>
<Button color="inherit">Basket</Button>
{fbContent}
</Toolbar>
</AppBar>
{fbContent}
</div>
);
}
}
I have also faced a situation like this, and this is really strange what I did was I took out everything and put inside separate component.
In your case you might want to take out all your Fb login functionality into a separate component and just import this component into your main component
makeStyles is a high order function which returns a hook (usually named useStyles) and hooks cannot be called from within class based components. This is the part throwing the error
classes = this.useStyles()
Use connect instead of makeStyles.
connect is a high order component which serializes classes inside both functional and class based components props
import { connect } from '#material-ui/core/styles'
class Component extends React.Component{
render(){
const { classes } = this.props
return <div className={classes.foo} />
}
}
export default connect(styles)(Component)
//Works in functional components as well
const Component = connect(styles)(({ classes }) =>{
return <div className={classes.foo} />
})

How can I convert popover MATERIAL-UI functional component to class based component?

I'm trying to convert this functional component to class based component. I have tried for several hours but could not find where to place these const variables in component. If someone could write it out in class based component it will highly appreciated.
const useStyles = makeStyles(theme => ({
typography: {
padding: theme.spacing(2),
},
}));
function SimplePopper() {
const classes = useStyles();
const [anchorEl, setAnchorEl] = React.useState(null);
function handleClick(event) {
setAnchorEl(anchorEl ? null : event.currentTarget);
}
const open = Boolean(anchorEl);
const id = open ? 'simple-popper' : null;
return (
<div>
<Button aria-describedby={id} variant="contained" onClick={handleClick}>
Toggle Popper
</Button>
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Paper>
<Typography className={classes.typography}>The content of the Popper.</Typography>
</Paper>
</Fade>
)}
</Popper>
</div>
);
}
export default SimplePopper;
import React, { Component } from "react";
import { createMuiTheme } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
import Button from "#material-ui/core/Button";
import Fade from "#material-ui/core/Fade";
import Paper from "#material-ui/core/Paper";
import Popper from "#material-ui/core/Popper";
import { withStyles } from "#material-ui/styles";
const theme = createMuiTheme({
spacing: 4
});
const styles = {
typography: {
padding: theme.spacing(2)
}
};
class SimplePopper extends Component {
constructor(props) {
super(props);
this.state = { anchorEl: null, open: false };
}
flipOpen = () => this.setState({ ...this.state, open: !this.state.open });
handleClick = event => {
this.state.ancherEl
? this.setState({ anchorEl: null })
: this.setState({ anchorEl: event.currentTarget });
this.flipOpen();
};
render() {
const open = this.state.anchorEl === null ? false : true;
console.log(this.state.anchorEl);
console.log(this.state.open);
const id = this.state.open ? "simple-popper" : null;
const { classes } = this.props;
return (
<div>
<Button
aria-describedby={id}
variant="contained"
onClick={event => this.handleClick(event)}
>
Toggle Popper
</Button>
<Popper
id={id}
open={this.state.open}
anchorEl={this.state.anchorEl}
transition
>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<Paper>
<Typography className={classes.typography}>
The content of the Popper.
</Typography>
</Paper>
</Fade>
)}
</Popper>
</div>
);
}
}
export default withStyles(styles)(SimplePopper);
First thing one need to understand is, how class based and functional components work. Also, when and where you use it.
In short, I can say functional components are Used for presenting static data. And class based are Used for dynamic source of data.
Here are few links for your reference.
Class based component vs Functional components what is the difference ( Reactjs ) and React functional components vs classical components
To answer your specific question.
import React, { Component } from 'react';
import { withStyles, makeStyles } from '#material-ui/styles';
const useStyles = makeStyles(theme => ({
typography: {
padding: theme.spacing(2),
},
}));
class SimplePopper extends Component {
constructor(props){
super(props)
this.state = { anchorEl: null, setAnchorEl: null }; <--- Here see the state creation
this.handleClick= this.handleClick.bind(this);
}
handleClick(event) {
const { anchorEl, setAnchorEl } = this.state; <--- Here accessing the state
setAnchorEl(anchorEl ? null : event.currentTarget);
}
render() {
const { anchorEl, setAnchorEl } = this.state; <--- Here accessing the state
const open = Boolean(anchorEl);
const id = open ? 'simple-popper' : null;
const { classes } = this.props;
return (
<div>
............Rest of the JSX............
</div>
);
}
}
export default withStyles(useStyles)(SimplePopper);
Note that here I've used withStyles to wrap the style to your component. So, that the styles will be available as classNames.
Explore the difference and convert the rest
This is more enough to begin with.

How to make a loading button in MUI?

I am using react with MUI framework and I was wondering how can I create an loading button using this framework?
I am looking for something similar to this.
To the best of my knowledge, there is no single component that accomplishes this out of the box in material-ui. However, you can implement your own easily using CircularProgress.
Assuming you are using material-ui v1, here's a rough example. First, I create a LoadingButton that accepts a loading prop - if that prop is true, I display a CircularProgress indicator. It also accepts a done prop - if that's true, the button clears the progress indicator and becomes a checkmark to show success.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Button from 'material-ui/Button';
import { CircularProgress } from 'material-ui/Progress';
import Check from 'material-ui-icons/Check';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
},
});
const LoadingButton = (props) => {
const { classes, loading, done, ...other } = props;
if (done) {
return (
<Button className={classes.button} {...other} disabled>
<Check />
</Button>
);
}
else if (loading) {
return (
<Button className={classes.button} {...other}>
<CircularProgress />
</Button>
);
} else {
return (
<Button className={classes.button} {...other} />
);
}
}
LoadingButton.defaultProps = {
loading: false,
done: false,
};
LoadingButton.propTypes = {
classes: PropTypes.object.isRequired,
loading: PropTypes.bool,
done: PropTypes.bool,
};
export default withStyles(styles)(LoadingButton);
You can use the LoadingButton as shown in the following example, which uses state to set the appropriate prop on the button.
import React from 'react';
import LoadingButton from './LoadingButton';
class ControlledButton extends React.Component {
constructor(props) {
super(props);
this.state = { loading: false, finished: false };
}
render() {
const { loading, finished } = this.state;
const setLoading = !finished && loading;
return (
<div>
<LoadingButton
loading={setLoading}
done={finished}
onClick={() => {
// Clicked, so show the progress dialog
this.setState({ loading: true });
// In a 1.5 seconds, end the progress to show that it's done
setTimeout(() => { this.setState({ finished: true })}, 1500);
}}
>
Click Me
</LoadingButton>
</div>
);
}
}
export default ControlledButton;
You can of course tweak the styling and functionality to meet your exact needs.
In the newer versions of MUI, you can use LoadingButton component, it's currently in the lab package. This is just a wrapper of the Button with a loading prop. You can customize the loadingIndicator component and its position. See the example below:
import LoadingButton from '#mui/lab/LoadingButton';
<LoadingButton loading={loading}>
Text
</LoadingButton>
<LoadingButton
endIcon={<SendIcon />}
loading={loading}
loadingPosition="end"
variant="contained"
>
Send
</LoadingButton>

Resources