我正在尝试将吐司通知添加到我的应用中,我一直在尝试使用的一个插件是react-toastify。
我遇到的问题可能更多是一般的react / redux问题,而不是像react-toastify这样的插件。
根据我对当前代码的了解,我正在使用化简器设置错误和成功消息的redux状态,每个错误或成功消息都将持久存储在存储中,直到调用另一个操作来清除它们为止。
我不知道的问题是如何仅触发一次吐司。例如。我输入了错误的凭据,它会创建错误的Toast,但是只要状态发生更改并重新加载(在电子邮件或密码字段中键入任何内容),都会创建另一个Toast。
如何让它只显示一次?
userActions.js
function handleErrors(res) {
if (res.ok) {
return res.json();
} else {
return res.json().then(err => {throw err;});
}
}
export const login = (user) => dispatch => {
fetch(`${url}/login`,
{
credentials: 'include',
method: 'post',
body: user,
headers: new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
})
.then(handleErrors)
.then(res =>
dispatch({
type: LOGIN,
payload: res
})
)
.catch(error =>
dispatch({
type: ERROR,
payload: error
})
)
}
userReducer.js
const initialState = {
errors: '',
success: ''
};
export default function(state = initialState, action) {
switch (action.type) {
case LOGIN:
return {
...state,
errors: '',
success: action.payload.message
};
case ERROR:
return {
...state,
success: '',
errors: action.payload.message
}
default:
return state;
}
}
app.js
app.post('/login', function(req, res) {
... return res.status(500).send({ message: 'Wrong credentials' });
... return res.status(200).send({ message: 'good!' });
});
login.js
class Login extends React.Component {
constructor() {
super();
this.state = {
email: "",
password: ""
}
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
}
render() {
const { errors, login, success } = this.props;
if (success !== '') toast.success(success, {
position: toast.POSITION.TOP_CENTER
});
if (errors !== '') toast.error(errors, {
position: toast.POSITION.TOP_CENTER
});
return (
<div>
<input type="text" id="email" placeholder="Email Address" onChange={this.handleChange} />
<input type="password" id="password" placeholder="Password" onChange={this.handleChange} />
<button onClick={() => login(JSON.stringify({email: this.state.email, password: this.state.password}))}>Log In</button>
<ToastContainer />
</div>
)
}
}
const mapStateToProps = state => ({
errors: state.store.errors,
success: state.store.success
});
export default connect(mapStateToProps, {login})(Login);
答案 0 :(得分:4)
您要在render内部调用toast.success或toast.error,这将在您每次重新渲染组件时弹出一个新的Toast。
解决方案很简单。将您的Toast调用移到render外部,在该调用中它们只会被调用一次。
一种实现此目的的方法是从userAction返回一个值。
export const login = (user) => dispatch => {
return new Promise((resolve, reject) => {
fetch(`${url}/login`,
{
credentials: 'include',
method: 'post',
body: user,
headers: new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json'
})
})
.then(handleErrors)
.then(res => {
dispatch({
type: LOGIN,
payload: res
})
resolve(res)
}
)
.catch(error => {
dispatch({
type: ERROR,
payload: error
})
reject(error)
}
)
}
}
然后使用该值在login.js中敬酒。
class Login ... {
...
loginUser = () => {
this.props.login(JSON.stringify({email: this.state.email, password: this.state.password}))
.then(res => {
toast.success(res.message, { position: toast.POSITION.TOP_CENTER })
}
).catch(error => {
toast.error(error.message, { position: toast.POSITION.TOP_CENTER })
}
)
}
...
render() {
return (
...
<button onClick={this.loginUser}>Log In</button>
...
)
}
}
还有其他方法可以实现相同的功能,并且根据项目的结构,您可能希望以更通用的方式来敬酒。