React getting Maximum update depth exceeded error - reactjs

I'm performing a change password, for authError I'm getting the following error..
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
changepassword.js
import React, { Component } from 'react'
import withStyles from "#material-ui/core/styles/withStyles";
import { Redirect } from 'react-router-dom'
import IconButton from '#material-ui/core/IconButton';
import { connect } from 'react-redux'
import { compose } from 'redux'
import {changePassword } from '../../store/actions/auth'
const styles = {
textField: {
fontSize: '5px'
},
};
class ChangePassword extends Component {
state = {
loading: false,
open:false,
message:'',
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: ''
}
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
openSnackbar = ({ message }) => {
this.setState({
open: true,
message,
});
};
handleSubmit = (e) => {
e.preventDefault();
let curpass=this.state.cp_currentPassword
let newpass=this.state.cp_newPassword
this.setState({loading:true});
this.props.changePassword(curpass,newpass)
this.openSnackbar({ message: 'Password changed Successfully.!' })
}
render() {
const { classes, auth, authError } = this.props;
const { loading } = this.state;
const message = (
<span
id="snackbar-message-id"
dangerouslySetInnerHTML={{ __html: this.state.message }}
/>
);
if (!auth.uid) return <Redirect to='/signin' />
return (
<div>
<GridContainer>
<GridItem xs={12} sm={12} md={12}>
<Card>
<CardHeader color="warning">
<h4 className={classes.cardTitleWhite}>Change Password</h4>
</CardHeader>
<form >
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<CardBody>
<GridContainer>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_currentPassword"
label="Current Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_currentPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_newPassword"
label="New Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_newPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_confirmPassword"
label="Confirm Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_confirmPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
</GridContainer>
</CardBody>
<CardFooter>
<Button color="warning" onClick={this.handleSubmit} disabled={loading}>
{loading && <CircularProgress style={{ color: 'white', height: '20px', width: '20px', marginRight: '10px' }} />}
Change Password
</Button>
</CardFooter>
</GridItem>
</GridContainer>
</form>
</Card>
</GridItem>
</GridContainer>
{authError ? this.openSnackbar({ message: '{authError}' }) : null}
<Snackbar
open={this.state.open}
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
message={message}
variant="error"
onClose={() => this.setState({ open: false, message: '' })}
action={
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={() => this.setState({ open: false, message: '' })}
>
<CloseIcon className={classes.icon} />
</IconButton>
}
autoHideDuration={3000}
/>
</div>
)
}
}
const mapstateToProps = (state) => {
return {
auth: state.firebase.auth,
authError: state.authroot.autherr
}
}
const mapDispatchtoProps = (dispatch) => {
return {
changePassword: (currentPassword,newPassword) => { dispatch(changePassword(currentPassword,newPassword)) }
}
}
export default compose(
withStyles(styles),
connect(mapstateToProps,mapDispatchtoProps)
)(ChangePassword);
change password action
export const changePassword = (currentPassword, newPassword) => {
return (dispatch, getState, { getFirebase }) => {
const firebase = getFirebase();
console.log(currentPassword);
console.log(newPassword);
var user = firebase.auth().currentUser;
user.updatePassword(newPassword).then(() => {
console.log("Password updated!");
}).catch((error) => {
dispatch({ type: 'CHANGEPASSWORD_ERR', error })});
}
}

You are updating state here
{authError ? this.openSnackbar({ message: '{authError}' }) : null
that line runs multiple times, as it checks if there was auth error, if there was call openSnackBar, openSnackBar update state, which cause the component to re-render, after re-render the check happens again etc, which causes a loop. change it to the following and only call openSnackBar when state.open is false.
{authError && !this.state.open ? this.openSnackbar({ message: '{authError}' }) : null}
EDIT
remove authError from render and check in componentDidMount
componentDidMount = () => {
const { authError } = this.props;
if (authError) {
this.openSnackbar({ message: '{authError}' });
}
};

Related

Why do I have to refresh my page to see my Card rendered?

I have a React+ Rails app .I am facing a small prob with my react application. Whenever I make a post request I am navigated to a page,but I cannot see my card rendered.After I refresh the page I can see the card getting rendered AND it ever persists on the page .Why do I have to refresh the page though?How to solve this?
Here is my code.I have added some MUI designing pardon me if thats confusing
Reservation Form
function ReservationForm() {
const navigate = useNavigate();
const params = useParams();
const { user,errors,setErrors } = useContext(Cont);
const [reservationData, setReservationData] = useState({
name: "",
date: "",
time: "",
num: "",
contact: "",
occasion: "",
});
function handleReservationChange(event) {
setReservationData({
...reservationData,
[event.target.name]: event.target.value,
});
}
function handleReservationChangeWithNameAndValue(name, newValue) {
setReservationData({
...reservationData,
[name]: newValue,
});
}
function handleReservationSubmit(event) {
event.preventDefault();
const newReservation = {
...reservationData,
restaurant_id: params.id,
user_id: user.id,
};
fetch(`/reservations`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newReservation),
})
.then((r) => r.json())
.then(
setReservationData({
name: "",
date: "",
time: "",
num: "",
contact: "",
occasion: "",
})
);
navigate("/myreservations");
}
return (
<>
<div className="overlay3">
<Box
component="form"
sx={{
"& > :not(style)": { m: 1 },
}}
noValidate
autoComplete="off"
onSubmit={handleReservationSubmit}
>
<h1 className="editheadings">Reserve 🍽️</h1>
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Name</InputLabel>
<OutlinedInput
type="text"
name="name"
id="name"
value={reservationData.name}
onChange={handleReservationChange}
label="Name"
/>
</FormControl>
<br />
<FormControl name="date" className="inputstyle">
<LocalizationProvider
dateAdapter={AdapterDayjs}
name="date"
fullWidth
>
<DatePicker
label="Date"
name="date"
value={reservationData.date || null}
onChange={(newVal) =>
handleReservationChangeWithNameAndValue("date", newVal)
}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
</FormControl>
<FormControl className="inputstyle">
<LocalizationProvider dateAdapter={AdapterDayjs}>
<TimePicker
name="time"
label="Time"
value={reservationData.time || null}
onChange={(newVal) =>
handleReservationChangeWithNameAndValue("time", newVal)
}
renderInput={(params) => <TextField {...params} />}
/>
</LocalizationProvider>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">No. of Guests</InputLabel>
<OutlinedInput
type="number"
name="num"
value={reservationData.num}
onChange={handleReservationChange}
/>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Contact</InputLabel>
<OutlinedInput
type="tel"
name="contact"
value={reservationData.contact}
onChange={handleReservationChange}
placeholder="contact"
/>
</FormControl>
<br />
<FormControl className="inputstyle">
<InputLabel htmlFor="component-outlined">Occasion</InputLabel>
<OutlinedInput
type="text"
name="occasion"
value={reservationData.occasion}
onChange={handleReservationChange}
/>
</FormControl>
<Stack paddingLeft={15} direction="row" id="loginbutton">
<ColorButton variant="contained" type="submit">
{" "}
Reserve
</ColorButton>
</Stack>
</Box>
</div>
</>
);
}
export default ReservationForm;
My Reservations
import {useEffect, useState } from "react";
import ReservationCard from "./ReservationCard";
import { useContext } from "react";
import { Cont } from "../Cont";
function MyReservations(){
const {reservations,setReservations}=useContext(Cont);
useEffect(()=>{
fetch("/reservations")
.then(res=>res.json())
.then(reservationData=>{
setReservations(reservationData)
})
},[])
function handleUpdateReservation(updatedReservation) {
const updatedReservations = reservations.map((reservation) => {
if (reservation.id === updatedReservation.id) {
return updatedReservation;
} else {
return reservation;
}
});
setReservations(updatedReservations);
}
function handleCancel(reservationtodelete){
const newReservations=reservations.filter(r=>r.id !== reservationtodelete)
setReservations(newReservations)
}
const renderReservations=reservations.map((reservation)=>(
<ReservationCard key={reservation.id} reservation={reservation} handleCancel={handleCancel} onUpdateReservation={handleUpdateReservation} />
))
return(
<>
{renderReservations}
</>
)
}
export default MyReservations;
Reservation Card
function ReservationCard({ reservation, handleCancel, onUpdateReservation }) {
const { name, date, time, num, contact, occasion } = reservation;
const [isEditing, setIsEditing] = useState(false);
const handleReservationUpdate = (updatedReservation) => {
setIsEditing(false);
onUpdateReservation(updatedReservation);
};
function handleDeleteClick() {
fetch(`/reservations/${reservation.id}`, {
method: "DELETE",
});
handleCancel(reservation.id);
}
return (
<>
{isEditing ? (
<Box m={4} sx={{ width: 500 }}>
<div className="overlay2">
<EditReservationForm
reservation={reservation}
onUpdateReservation={handleReservationUpdate}
/>
</div>
</Box>
) : (
<>
<Box m={4} sx={{ width: 500 }}>
<Card width={5}>
<CardContent>
<Typography variant="h5" component="div">
{reservation.restaurant.name}
</Typography>
<br />
<Typography sx={{ mb: 1.5 }} color="text.secondary">
Guest Details
</Typography>
<Typography variant="h6" component="div">
{name}
</Typography>
<Typography variant="h6">{contact}</Typography>
<Typography variant="h6">Date:{date}</Typography>
<Typography variant="h6">Time : {time}</Typography>
<Typography variant="h6">Guests : {num}</Typography>
<Typography variant="h6">Occasion:{occasion}</Typography>
</CardContent>
<CardActions>
<Button onClick={() => setIsEditing((isEditing) => !isEditing)}>
{" "}
Modify Booking
</Button>
<Button onClick={handleDeleteClick}>Cancel Booking</Button>
</CardActions>
</Card>
</Box>
</>
)}
</>
);
}
export default ReservationCard;
Fetch is an async promise function, so you'd need to use .then or await to make sure to receive the response.
const response = await fetch(
`http://localhost:8080/api/user/login?username=${uname}&password=${pass}`, {
method: 'POST'
}
);
const userData = await response.json();

want to create a redux form(in a modal) which will performs of post request to a any given database

a react beginner
want to create a redux form(in a modal) which will performs of post request to a any given database > this is how the modal looks
youll see that ive defined a separate state for each and every input, slider and switch relating which i was confused so as how to call them
can someone please check this out and give a possible solution. Thankyou
import React,{ useState } from 'react'
import clsx from 'clsx'
import { Form, Modal, Button, Container, Row, Col } from 'react-bootstrap'
import { withStyles } from '#material-ui/core/styles';
import './Tasks.css'
import { Slider, Switch, FormControlLabel, TextField, makeStyles} from '#material-ui/core'
import { Field, reduxForm } from 'redux-form'
import AddIcon from '#material-ui/icons/Add'
import { createMuiTheme } from "#material-ui/core/styles";
import { ThemeProvider } from "#material-ui/styles";
this is where ive defined styles for some of the components
const useStyles = makeStyles((theme)=> ({
margin: {
margin:theme.spacing(1)
},
textField: {
width: '40ch',
}
}))
const BlueSwitch = withStyles({
switchBase: {
color: "#29b6f6",
'&$checked': {
color: "#29b6f6",
},
'&$checked + $track': {
backgroundColor: "#29b6f6",
},
},
checked: {},
track: {},
})(Switch);
const muiTheme = createMuiTheme({
overrides: {
MuiSlider: {
thumb: {
color: "#29b6f6"
},
track: {
color: "#29b6f6"
},
rail: {
color: "black"
}
}
}
});
styles ended
validate function, not able to determine whether its working or not
const validate = values => {
const errors = {}
const requiredFields = [ 'email', 'recoverymail', 'password', 'securityans' ]
requiredFields.forEach(field => {
if (!values[ field ]) {
errors[ field ] = 'Required'
}
})
if (values.email && !/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address'
}
return errors
}
const Tasks = (props) => {
const { handleSubmit } = props
const classes = useStyles();
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
ive defined this particular state for the slider but thought just by calling the values like {runtime_min, runtime_max, sleeptime_min, sleeptime_max } in the value props of each of the sliders, but im not sure now nor i know any other way of defining its state
const [{runtime_min, runtime_max, sleeptime_min, sleeptime_max }, setValue] = React.useState(30);
const handleChange = (event, newValue) => {
setValue(newValue)
}
const [security, setState] = React.useState({
email: '',
recoverymail: '',
passowrd: '',
securityans:'',
runtime_min: '',
runtime_max: '',
sleeptime_min: '',
sleeptime_max: ''
});
const updateInfo = (event, inputValue ) => {
let inputField = event.target.name;
//let inputValue = event.target.value;
if( inputField === 'email'){
setState({ email: inputValue })
}
else if( inputField === 'recoverymail'){
setState({ email: inputValue })
}
else if( inputField === 'password'){
setState({ password: inputValue })
}
else if( inputField === 'securityans'){
setState({ securityans: inputValue })
}
else if( inputField === 'runtime_min'){
setState({ runtime_min: inputValue })
}
else if( inputField === 'runtime_max'){
setState({ runtime_max: inputValue })
}
else if( inputField === 'sleeptime_min'){
setState({ sleeptime_min: inputValue })
}
else if( inputField === 'sleeptime_max'){
setState({ sleeptime_max: inputValue })
}
}
on click of the create task button given below itll call this function and post all the given details
const create_task =(e)=>{
let{ email, recoverymail, passowrd, securityans, runtime_min, runtime_max, sleeptime_min, sleeptime_max } = this.state;
fetch('db_name', {
method: 'post',
headers: { 'Content=Type': 'application/json' },
body: JSON.stringify({
email : email,
recoverymail : recoverymail,
passowrd : passowrd,
securityans : securityans,
runtime_min : runtime_min,
runtime_max : runtime_max,
sleeptime_min : sleeptime_min,
sleeptime_max: sleeptime_max
})
}).then(response => response.json()).then(data => {
window.alert(data)
})
};
const [state, setStatei] = React.useState({
checkedA: true,
checkedB: true,
checkedC: true,
checkedD: true,
checkedE: true
});
const handleChangei = (event) => {
setStatei({ ...state, [event.target.name]: event.target.checked });
};
const renderTextField = ({ input, label, meta: { touched, error, invalid }, ...custom }) => (
<TextField hintText={label}
id="outlined-basic"
variant="outlined"
label={label}
placeholder={label}
error={touched && invalid}
helperText={touched && error}
input={security.state}
{...custom}
/>
)
return(
<Button className="b1" onClick={handleShow}>+ Create Task</Button>
<Container>
<Modal show={show} onHide={handleClose} className="modal-dialog modal-lg">
<Modal.Header className="modal-head" closeButton>
<Modal.Title> Create Task</Modal.Title>
</Modal.Header>
<Modal.Body className="modal-body" onSubmit={handleSubmit}>
<Row>
<Col>
<Field className={clsx(classes.margin, classes.textField)} component={renderTextField} placeholder="Email" onChange={updateInfo} name="email" value={security.email}/>
</Col>
<Col>
<Field className={clsx(classes.margin, classes.textField)} component={renderTextField} placeholder="Recovery Email" onChange={updateInfo} name="recoverymail" value={security.recoverymail}/>
</Col>
</Row>
<Row>
<Col>
<Field className={clsx(classes.margin, classes.textField)} component={renderTextField} placeholder="Password" onChange={updateInfo} name="passowrd" value={security.passowrd}/>
</Col>
<Col>
<Field className={clsx(classes.margin, classes.textField)} component={renderTextField} placeholder="Security Answer" onChange={updateInfo} name="securityans" value={security.securityans}/>
</Col>
</Row>
<>
<Container class="set-ci">
<Row>
<Col>
<text className="text-ci">Run Time</text> <b> Minimum</b>
<ThemeProvider theme={muiTheme}>
<Slider
value={runtime_min}
onChange={handleChange}
aria-labelledby="discrete-slider-always"
step={10}
valueLabelDisplay="auto"
/>
</ThemeProvider>
</Col>
<Col>
<text className="text-ci">Run Time </text> <b> Maximum</b>
<ThemeProvider theme={muiTheme}>
<Slider
value={runtime_max}
onChange={handleChange}
aria-labelledby="discrete-slider-always"
step={10}
valueLabelDisplay="auto"
/>
</ThemeProvider>
</Col>
</Row>
<Row>
<Col>
<text className="text-ci">Sleep Time </text> <b> Minimum</b>
<ThemeProvider theme={muiTheme}>
<Slider
value={sleeptime_min}
onChange={handleChange}
aria-labelledby="discrete-slider-always"
step={10}
valueLabelDisplay="auto"
/>
</ThemeProvider>
</Col>
<Col>
<text className="text-ci">Sleep Time </text> <b> Maximum</b>
<ThemeProvider theme={muiTheme}>
<Slider
value={sleeptime_max}
onChange={handleChange}
aria-labelledby="discrete-slider-always"
step={10}
valueLabelDisplay="auto"
/>
</ThemeProvider>
</Col>
</Row>
</Container>
</>
<Row className="foot-row">
<Col>
<Row>
<Col>
<FormControlLabel
className="set-fcl"
control=
{
<BlueSwitch
checked={state.checkedA}
onChange={handleChangei}
name="checkedA"
/>
}
label="Youtube"
/>
</Col>
<Col>
<FormControlLabel
className="set-fcl"
control=
{
<BlueSwitch
checked={state.checkedB}
onChange={handleChangei}
name="checkedB"
/>
}
label="Shopping"
/>
</Col>
</Row>
<Row>
<Col>
<FormControlLabel
className="set-fcl"
control=
{
<BlueSwitch
checked={state.checkedC}
onChange={handleChangei}
name="checkedC"
/>
}
label="Images"
/>
</Col>
<Col>
<FormControlLabel
className="set-fcl"
control=
{
<BlueSwitch
checked={state.checkedD}
onChange={handleChangei}
name="checkedD"
/>
}
label="Search"
/>
</Col>
</Row>
<Row>
<Col>
<Form>
<FormControlLabel
className="set-fcl"
control=
{
<BlueSwitch
checked={state.checkedE}
onChange={handleChangei}
name="checkedE"
/>
}
label="News"
/>
</Form>
</Col>
<Col className="generate-col">
<Button className="generate" onClick={create_task} type="submit" > <AddIcon/> Create Task </Button>
</Col>
</Row>
</Col>
</Row>
</Modal.Body>
</Modal>
</Container>
);
}
export default reduxForm({
form: 'simple',
validate
})(Tasks)
onclick of the create task button i get an error stating "TypeError: Cannot read property 'state' of undefined" which im not able to debug
for my view i see that maybe you a make a mistake when you try to use destructing with "this.state" , this isn´t a class component, instead of you should only use state.
let{ email, recoverymail, passowrd, securityans, runtime_min, runtime_max, sleeptime_min, sleeptime_max } = state
but too i see that properties doesn`t exist in the state that you call, that propertis are in security, then ...
let{ email, recoverymail, passowrd, securityans, runtime_min, runtime_max, sleeptime_min, sleeptime_max } = security
You are using this.state instead of security.
let { email, recoverymail, passowrd, securityans, runtime_min, runtime_max, sleeptime_min, sleeptime_max } = security;
Since you are using functional component and state hook, you can't access the state's value using this.state as it is only used on class based components.
I encourage you to read more on React Hooks as you are using some of them wrong.
Edit:
For setValue, it's better to use the security state and modify it rather than creating another. One thing to modify it is
const handleChange = (event, newValue) => {
// assign security to a new variable, we shouldn't modify states directly
let securityData = security;
// then modify the properties that you want
securityData.runtimemin = 30;
securityData.runtimemax = 30;
// then fire up the setState hook and passing your modified object
setState(securityData);
}

Failed prop type: Material-UI: Either `children`, `image`, `src` or `component` prop must be specified in ForwardRef(CardMedia)

Whenever I'm trying to post new Screams in my page. I'm not getting the image, title and content of the card. I need to reload to get that.
It is saying failed prop types means after posting a scream I'm not getting the value from prop types but after a reload, everything seems to be fine. I don't know what is wrong is going. Please have a look at my code.
This is my Screams.js from where i'm showing my Screams
Scream.js
const styles = {
card: {
position: "relative",
display: "flex",
marginBottom: 20,
},
image: {
minWidth: 150,
},
content: {
padding: 25,
objectFit: "cover",
},
};
class Scream extends Component {
render() {
dayjs.extend(relativeTime);
const {
classes,
scream: {
body,
createdAt,
userImage,
userHandle,
screamId,
likeCount,
commentCount,
},
user: {
authenticated,
credentials: { handle },
},
} = this.props;
const deleteButton =
authenticated && userHandle === handle ? (
<DeleteScream screamId={screamId} />
) : null;
const likeButton = !authenticated ? (
<Link to="/login">
<MyButton tip="Like">
<FavoriteBorder color="primary" />
</MyButton>
</Link>
) : this.likedScream() ? (
<MyButton tip="Undo like" onClick={this.unlikeScream}>
<FavoriteIcon color="primary" />
</MyButton>
) : (
<MyButton tip="Like" onClick={this.likeScream}>
<FavoriteBorder color="primary" />
</MyButton>
);
return (
<Card className={classes.card}>
<CardMedia
image={userImage}
title="Profile Image"
className={classes.image}
/>
<CardContent className={classes.content}>
<Typography variant="h5" component={Link} to={`/users/${userHandle}`}>
{userHandle}
</Typography>
{deleteButton}
<Typography variant="body2" color="textSecondary">
{dayjs(createdAt).fromNow()}
</Typography>
<Typography variant="body1">{body}</Typography>
{likeButton}
<span> {likeCount} Likes </span>
<MyButton tip="comments">
<ChatIcon color="primary" />
</MyButton>
<span> {commentCount} Comments </span>
</CardContent>
</Card>
);
}
}
Scream.propTypes = {
likeScream: PropTypes.func.isRequired,
unlikeScream: PropTypes.func.isRequired,
user: PropTypes.object.isRequired,
scream: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
};
const mapStateToprops = (state) => ({
user: state.user,
});
const mapActionToProps = {
likeScream,
unlikeScream,
};
export default connect(
mapStateToprops,
mapActionToProps
)(withStyles(styles)(Scream));
As u can see i have userImage, userHandle and body of the card in the props and it is showing it on my page.
But after posting a new Scream, i'm not getting the image, userHandle and body of the new Scream unless and until reload it.
PostScream.js
class PostScream extends Component {
state = {
open: false,
body: "",
errors: {}
}
componentWillReceiveProps(nextProps) {
if(nextProps.UI.errors) {
this.setState({
errors: nextProps.UI.errors
});
}
if(!nextProps.UI.errors && !nextProps.UI.loading) {
this.setState({
body: "",
open: false,
errors: {}
})
}
}
handleOpen = () => {
this.setState({ open: true })
};
handleClose = () => {
this.props.clearErrors();
this.setState({ open: false, errors: {} });
};
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value })
}
handleSubmit = (event) => {
event.preventDefault();
this.props.postScream({ body: this.state.body })
}
render() {
const { errors } = this.state;
const { classes, UI: { loading }} = this.props;
return (
<Fragment>
<MyButton onClick= { this.handleOpen } tip="Post a Scream!">
<AddIcon />
</MyButton>
<Dialog
open= { this.state.open }
onClose= { this.handleClose }
fullWidth
maxWidth = "sm"
>
<MyButton
tip="Close"
onClick={this.handleClose}
tipClassName={classes.closeButton}
>
<CloseIcon />
</MyButton>
<DialogTitle> Post a new Scream </DialogTitle>
<DialogContent>
<form onSubmit= { this.handleSubmit }>
<TextField
name="body"
type="text"
label="SCREAM!"
multiline
rows="3"
placeholder= "What's on your mind!"
error={ errors.body ? true: false }
helperText={ errors.body }
className={classes.TextField}
onChange={ this.handleChange }
fullWidth
/>
<Button
type="submit"
variant="contained"
color="primary"
className={classes.submitButton}
disabled={ loading }
>
Submit
{loading && (
<CircularProgress size={30} className={ classes.progressSpinner } />
)}
</Button>
</form>
</DialogContent>
</Dialog>
</Fragment>
)
}
}
PostScream.propTypes = {
postScream: PropTypes.func.isRequired,
clearErrors: PropTypes.func.isRequired,
UI: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
UI: state.UI
});
export default connect(
mapStateToProps,
{ postScream, clearErrors }
)(withStyles(styles)(PostScream));
After posting a new Scream, i am getting Scream like this:-
I was having the same issue, I was able to fix it by adding component='img' to my CardMedia.
<CardMedia
image={userImage}
title="Profile Image"
className={classes.image}
component='img'
/>
Specifying the component as an img "Hides" the images since CardMedia is a div and your css is applied to the div. Add component = "div" to CardMedia.
<CardMedia
image={userImage}
title="Profile Image"
className={classes.image}
component='div'
/>

Reactjs push route after dispatch

Hello I am having trouble finding where I can call a route with push after authenticating the user
I did it using redux
my action:
const AuthenticateUser = (login, password) => {
    return dispatch => {
        dispatch (startAuth ());
        // fetching data
        api.post ('/ login', {login, password})
            .then (response => {
            localStorage.setItem ('token', response.data [0]);
            dispatch (userAuthenticated (response.data [1]))
        })
            .catch (err => {console.error (err);});
    }
}
export default AuthenticateUser;
my reducer:
const authReducer = (state = initialState, action) => {
    switch (action.type) {
        case USER_AUTHENTICATED:
            return {
                ... state,
                loading: false,
                authenticated: true,
                user: action.user,
            }
        case USER_FAILED_AUTH:
            return {
                ... state,
                loading: false,
                message: action.error
            }
        default:
        return state;
    }
}
and my form
const SignIn = (props) => {
const classes = useStyles();
const dispatch = useDispatch();
const [login, setLogin] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault()
dispatch(auth(login, password))
}
return (
<div className={classes.root}>
<Grid container spacing={2} className={classes.gridMain}>
<Grid item lg={12} md={12} sm={12} xs={12} align="center">
<img src={require("../nodejs-icon.svg")} alt="bug" height={100} />
</Grid>
<Grid item lg={12} md={12} sm={12} xs={12} className={classes.TextField}>
<form onSubmit={handleSubmit}>
<TextField
className={classes.input2}
id="demo2"
label="Usuário"
variant="outlined"
value={login}
onChange={(e) => setLogin(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<PersonSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<TextField
className={classes.txtFd}
id="demo2"
label="Senha"
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
InputLabelProps={{
classes: {
root: classes.label,
focused: classes.focusedLabel,
error: classes.erroredLabel
}
}}
InputProps={{
classes: {
root: classes.cssOutlinedInput,
focused: classes.cssFocused,
notchedOutline: classes.notchedOutline,
},
startAdornment: (
<InputAdornment position="start">
<LockSharpIcon style={{ fontSize: 25, color: 'rgba(20, 176, 12,0.9)' }} />
</InputAdornment>
)
}}
/>
<ButtonBase variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
<Typography noWrap className={classes.labelForgot} variant="subtitle2">
Esqueci minha senha
</Typography>
</ButtonBase>
<Button type="submit" className={classes.button} variant="raised" disableFocusRipple="false" disableRipple="false" centerRipple="false">
Entrar
</Button>
</form>
</Grid>
I have a route and after I authenticate this user I wanted to send it to a route or display an error msg, but I don't know where in the code to do it and how I would get it.
my route
const AppRouter = () => (
<BrowserRouter>
<Route path="/xd" component={AuthPage} exact={true} />
<Route path="/dashboard/addProduct" component={AddProduct} exact={true} />
</BrowserRouter>
);
So this is in order to give you an answer that is readable instead of using the comments.
In your SignIn component:
import { withRouter } from "react-router-dom";
const SignIn = (props) => {
const { history } = props;
const { push } = history;
// more variables
const handleSubmit = (e) => {
e.preventDefault()
// You pass the push function over here.
dispatch(auth(login, password, push))
}
// Rest of the logic
}
export default withRouter(SignIn);
The withRouter would give you all the props that are coming from react-router, this will allow you to use the history object, which contains the push function, to redirect the user to the page you want.
Then in your authenticate function which I'm guessing is the ´AuthenticateUser´ function you could do this:
const AuthenticateUser = (login, password, push) => {
return dispatch => {
dispatch (startAuth ());
// fetching data
api.post ('/ login', {login, password})
.then (response => {
localStorage.setItem ('token', response.data [0]);
dispatch (userAuthenticated (response.data [1]))
// push goes here
push("/your-awesome-route")
})
.catch (err => {console.error (err);});
}
}
export default AuthenticateUser;
You may use useEffect in SignIn component, which checks for flag authenticated: true (where this variable is passed via props) and does the redirection.
Something like that
useEffect(() => {
const { authenticated, navigation } = props;
if (authenticated) {
navigation.navigate(Routes.GoodPlace);
}
});

react- setState doesn't clear textbox

I want to clear textbox fields on success or error. how can I do that.?
On success or error, calling a function to show the snack bar. Within that, I'm updating the state. but it is not working fine.
any help appreciated.!
function
openSnackbar = ({ message }) => {
this.setState({
open: true,
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: '',
message
});
};
textfield
<TextField
id="cp_currentPassword"
label="Current Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_currentPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>;
component
import React, { Component } from 'react'
import withStyles from "#material-ui/core/styles/withStyles";
import CircularProgress from '#material-ui/core/CircularProgress';
import TextField from '#material-ui/core/TextField';
import GridItem from "../uiComponents/Grid/GridItem.jsx";
import GridContainer from "../uiComponents/Grid/GridContainer.jsx";
import Button from "../uiComponents/CustomButtons/Button.jsx";
import Card from "../uiComponents/Card/Card.jsx";
import CardHeader from "../uiComponents/Card/CardHeader.jsx";
import CardBody from "../uiComponents/Card/CardBody.jsx";
import CardFooter from "../uiComponents/Card/CardFooter.jsx";
import Snackbar from '#material-ui/core/Snackbar';
import CloseIcon from '#material-ui/icons/Close';
import { Redirect } from 'react-router-dom'
import IconButton from '#material-ui/core/IconButton';
import { connect } from 'react-redux'
import { compose } from 'redux'
import { changePassword } from '../../store/actions/auth'
const styles = {
textField: {
fontSize: '5px'
},
};
class ChangePassword extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
open: false,
message: '',
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: ''
}
}
componentDidUpdate = (prevProps) => {
const { authError } = this.props;
console.log(authError)
if (authError != prevProps.authError) {
this.setState(
{
loading: false,
message: authError,
open: true
})
}
};
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value
})
}
openSnackbar = ({ message }) => {
this.setState({
open: true,
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: '',
message
});
};
handleSubmit = (e) => {
e.preventDefault();
let curpass = this.state.cp_currentPassword
let newpass = this.state.cp_newPassword
this.setState({ loading: true });
this.props.changePassword(curpass, newpass, this.passwordUpdated)
}
passwordUpdated = () => {
this.setState({
message: 'Password changed Successfully.!',
open: true,
loading: false,
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: ''
});
};
render() {
const { classes, auth, authError } = this.props;
console.log(authError)
const { loading } = this.state;
const message = (
<span
id="snackbar-message-id"
dangerouslySetInnerHTML={{ __html: this.state.message }}
/>
);
if (!auth.uid) return <Redirect to='/signin' />
return (
<div>
{/* {authError ? this.openSnackbar({ message: '{authError}' }) : null} */}
{/* {authError && !this.state.open ? this.openSnackbar({ message: '{authError}' }) : null} */}
<GridContainer>
<GridItem xs={12} sm={12} md={12}>
<Card>
<CardHeader color="warning">
<h4 className={classes.cardTitleWhite}>Change Password</h4>
</CardHeader>
<form >
<GridContainer>
<GridItem xs={12} sm={12} md={6}>
<CardBody>
<GridContainer>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_currentPassword"
label="Current Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_currentPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_newPassword"
label="New Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_newPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
<GridItem xs={12} sm={12} md={12}>
<TextField
id="cp_confirmPassword"
label="Confirm Password"
type="password"
fullWidth
className={classes.textField}
value={this.state.cp_confirmPassword}
onChange={this.handleChange}
margin="normal"
required={true}
/>
</GridItem>
</GridContainer>
</CardBody>
<CardFooter>
<Button color="warning" onClick={(e) => this.handleSubmit(e)} disabled={loading}>
{loading && <CircularProgress style={{ color: 'white', height: '20px', width: '20px', marginRight: '10px' }} />}
Change Password
</Button>
</CardFooter>
</GridItem>
</GridContainer>
</form>
</Card>
</GridItem>
</GridContainer>
<Snackbar
open={this.state.open}//{!!this.props.authError}//
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
message={message}
variant="error"
onClose={() => this.setState({ open: false, message: '' })}
action={
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={() =>
// clearAuthError
this.setState({ open: false, message: '' })
}
>
<CloseIcon className={classes.icon} />
</IconButton>
}
autoHideDuration={3000}
/>
</div>
)
}
}
const mapstateToProps = (state) => {
return {
auth: state.firebase.auth,
authError: state.authroot.autherr
}
}
const mapDispatchtoProps = (dispatch, getState) => {
return {
changePassword: (currentPassword, newPassword, passwordUpdated) => { dispatch(changePassword(currentPassword, newPassword, passwordUpdated)) },
}
}
export default compose(
withStyles(styles),
connect(mapstateToProps, mapDispatchtoProps)
)(ChangePassword);
In your handleSubmit function don't pass this.passwordUpdated
handleSubmit = (e) => {
e.preventDefault();
let curpass = this.state.cp_currentPassword
let newpass = this.state.cp_newPassword
this.setState({ loading: true });
this.props.changePassword(curpass, newpass, this.passwordUpdated) //Remove this.passwordUpdated from here
}
Instead of ComponentDidUpdate method you should use ComponentWillReceiveProps
componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps', nextProps);
if (this.props.authError !== nextProps.authError) {
// here you can make your textbox empty
this.setState({
cp_currentPassword: '',
cp_newPassword: '',
cp_confirmPassword: ''
});
}
}
Note: In new version of react you must use static getDerivedStateFromProps() instead of componentWillReceiveProps.

Resources