【问题标题】:showing success and error messages in react/redux app在 react/redux 应用程序中显示成功和错误消息
【发布时间】:2018-12-15 14:56:51
【问题描述】:

我正在尝试向我的应用添加 toast 通知,我一直在尝试使用的一个插件是 react-toastify。

我遇到的问题可能更多是一般的 react/redux 问题,而不是 react-toastify 之类的插件。

我正在使用 reducer 为错误和成功消息设置 redux 状态,根据我对当前代码的理解,每个错误或成功消息都在存储中持久存在,直到调用另一个操作来清除它们。

我想不通的问题是如何只触发一次 toast。例如。我输入了错误的凭据,它会创建一个错误的 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);

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    您在 render 中调用 toast.success 或 toast.error ,每次重新渲染组件时都会弹出一个新的 toast。

    解决方案很简单。将你的 toast 调用移到渲染之外,它们只会被调用一次。

    实现此目的的一种方法是从您的 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>
                ...
            )
        }
    }
    

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

    【讨论】:

    • 这更有意义!但我收到此错误语法错误:意外令牌,预期,(19:13)17 |有效载荷:res 18 | }) > 19 |解决(res) | ^ 20 | ) 21 | .catch(error => 22 | dispatch({
    • 这个错误弹出是因为我忘记了一些大括号。我将使用修复程序编辑帖子。
    • 使用异步等待而不是承诺会更干净吗?
    • async-await vs. promises 是一个主观偏好调用,但您应该始终使用您正在处理的项目中已经使用的任何一个。避免将两者混为一谈。
    • 这是一个更好的解决方案,它有一种命令式的通知方式,因此代码容易出错。
    猜你喜欢
    • 1970-01-01
    • 2016-12-14
    • 2021-01-27
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2017-08-21
    • 2016-10-16
    • 1970-01-01
    相关资源
    最近更新 更多