在react / redux应用中显示成功和错误消息

时间:2018-07-07 04:23:35

标签: reactjs redux react-redux

我正在尝试将吐司通知添加到我的应用中,我一直在尝试使用的一个插件是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);

1 个答案:

答案 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>
            ...
        )
    }
}

还有其他方法可以实现相同的功能,并且根据项目的结构,您可能希望以更通用的方式来敬酒。