Я выполняю опцию смены пароля с помощью react-redux-firestore. Смена пароля работает нормально, если все введено правильно. Если какая-либо ошибка аутентификации получена, ошибка отправляется, и это должно отображаться пользователю. Всякий раз, когда была получена ошибка аутентификации, я обрабатывал ее следующим образом, чтобы показать сообщение об ошибке в рендере.
{authError ? this.openSnackbar({ message: '{authError}' }) : null}
но это делает бесконечный цикл.
Позже добавлен метод componentDidMount(). Это предотвратит зацикливание, но я не могу показать сообщение об ошибке.
componentDidMount = () => {
const { authError } = this.props;
console.info(authError)
if (authError) {
this.setState(
{
loading: false,
message: '{authError}',
open: true
},
() => {
alert(this.state.open);
}
)
}
};
когда я делаю console.info(authError).. сообщение об ошибке не отображается.
при нажатии кнопки, как я могу показать сообщение об ошибке?
Любая помощь приветствуется.
изменить компонент пароля
import React, { Component } from 'react'
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: ''
}
}
componentDidMount = () => {
const { authError } = this.props;
console.info('did mount called')
console.info(authError)
if (authError) {
this.setState(
{
loading: false,
message: '{authError}',
open: true
},
() => {
alert(this.state.open);
}
)
}
};
handleChangeEvent = (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.passwordUpdated)
}
passwordUpdated = () => {
this.setState({
message: 'Password changed Successfully.!',
open: true,
loading: false
});
};
render() {
const { classes, auth, authError } = this.props;
console.info(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} */}
<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.handleChangeEvent}
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.handleChangeEvent}
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.handleChangeEvent}
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}
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, getState) => {
return {
changePassword: (currentPassword, newPassword, passwordUpdated) => { dispatch(changePassword(currentPassword, newPassword, passwordUpdated)) }
}
}
export default compose(
withStyles(styles),
connect(mapstateToProps, mapDispatchtoProps)
)(ChangePassword);
действие авторизации
export const changePassword = (currentPassword, newPassword, func) => {
return (dispatch, getState, { getFirebase }) => {
const firebase = getFirebase();
var user = firebase.auth().currentUser;
var cred = firebase.auth.EmailAuthProvider.credential(
user.email, currentPassword);
// reauthenticateAndRetrieveDataWithCredential
user.reauthenticateWithCredential(cred)
.then(() => {
user.updatePassword(newPassword).then(() => {
console.info("Password updated!");
func();
}).catch((error) => { dispatch({ type: 'CHANGEPASSWORD_ERR', error }) });
}).catch((error) => {
dispatch({ type: 'CHANGEPASSWORD_CURRPSW_ERR', error })
});
}
}
Редуктор авторизации
case 'CHANGEPASSWORD_SUCCESS':
return {
...state,
//action.func
};
case 'CHANGEPASSWORD_CURRPSW_ERR':
return {
...state,
autherr: action.error.message
};
case 'CHANGEPASSWORD_ERR':
return {
...state,
autherr: action.error.message
};
выложил код компонента
Я думаю, что то, чего вы пытаетесь достичь, связано не с реквизитом, а с состоянием (состояние Redux, которое передается props
). Когда состояние изменяется, вы хотите, чтобы ошибка всплывала. В этом случае вы должны использовать componentDidUpdate
, а не componentDidMount
, потому что последний будет запускаться только один раз при монтировании компонента.
componentDidUpdate = (prevProps) => {
const { authError } = this.props;
console.info(authError)
if (authError != prevProps.authError) {
this.setState(
{
loading: false,
message: authError,
open: true
},
() => {
alert(this.state.open);
}
)
}
};
лучше сравнить точную опору, которая требует выполнения вышеуказанной логики, если есть другие опоры или состояние, которые будут меняться, это приведет к вечному циклу. поскольку вы вызываете setstate внутри.
Я согласен, хотя ansh не предоставил нам достаточно контекста, чтобы сделать это.
Обновил мой код, не должен создавать бесконечный цикл.
Просто установите открытый реквизит компонента Snackbar прямо из реквизита, например:
<Snackbar
open = {!!this.props.authError}
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 = {() =>{have a action dispatch for clear error added into the reducer}}
>
<CloseIcon className = {classes.icon} />
</IconButton>
}
autoHideDuration = {3000}
/>
Пожалуйста, выложите весь код компонента