如何从redux连接函数抛出“冒泡”错误?

时间:2018-03-12 00:03:02

标签: reactjs react-native redux redux-thunk

我希望我的本机应用程序能够显示带有Toast的错误消息。我想使用App检测根级componentDidCatch组件中的错误,以便以相同的方式处理所有错误。

目前,如果我的一个异步操作引发错误,mapDispatchToProps可以捕获它。如何将这些错误“冒泡”到我的App组件?

或者,我可以为错误添加redux状态,并在每个异步错误上设置它。然后,我可以在App中检查此状态。但是,如果我可以捕获componentDidCatch

中的所有错误,那将更清晰

2 个答案:

答案 0 :(得分:1)

嗯,这就是我在项目中所做的。我使用https://github.com/fkhadra/react-toastify

<强> App.js

import  Toaster  from './components/Toaster/Toaster';

class App extends Component {
    render() {
        return (
            <div>
                <Toaster/>
                <Routes />
            </div>
        );
    }
}

export default (App);

<强> Toaster.js

import React, { Component } from 'react';
import { connect } from "react-redux";
import { toast, ToastContainer } from 'react-toastify';
import PropTypes from 'prop-types';
import { toastConstants } from '../../_constants';

const Message = ({ type, content }) => {
    let icon = '';
    switch(type){
        case 'success':
            icon = <i className="fa fa-check-circle"></i>;
        break;
        case 'error': 
            icon = <i className="fa fa-times-circle"></i>;
        break;
        case 'info': 
            icon = <i className="fa fa-info-circle"></i>;
        break;
        case 'warning': 
            icon = <i className="fa fa-exclamation-circle"></i>;
        break;
        default:
            icon = ''; 
        break;
    }
    return (
        <div>
             {icon} {content}
        </div>
    );
};

class Toaster extends Component {
    componentWillReceiveProps(nextProps) {
        if (nextProps.toast.message && nextProps.toast.type) { 
            toast.dismiss();    
            switch (nextProps.toast.type) {
                case toastConstants.SUCCESS:
                    toast.success(<Message content={nextProps.toast.message} type="success" />);
                    break;
                case toastConstants.INFO:
                    toast.info(<Message content={nextProps.toast.message} type="info" />);
                    break;
                case toastConstants.WARN:
                    toast.warn(<Message content={nextProps.toast.message} type="warning" />);
                    break;
                case toastConstants.ERROR:
                    toast.error(<Message content={nextProps.toast.message} type="error" />);
                    break;
                default:
                    break;
            }
        }
    }
    render() {
        return (
            <ToastContainer autoClose={5000} />
        );
    }
}

function mapStateToProps(state) {
    const { toast } = state;
    return {
        toast
    };
}

Message.propTypes = {
    type: PropTypes.string,
    content: PropTypes.string
};

export default connect(mapStateToProps)(Toaster);

<强> SomeActions.js

function getAll(){
    return dispatch => {
        dispatch(request());
        companyService.getAll()
            .then(
                response => {
                    if(response.status === 'fail'){
                        dispatch(failure(response));
                        dispatch(toastActions.error(response.message));
                    }else{
                        dispatch(success(response));
                    }
                },
                error => {
                    dispatch(toastActions.error(error.toString()));
                    dispatch(failure(error.toString()));
                }
            );
    }
    function request() { return { type: companyConstants.LIST_REQUEST } }
    function success(data) { return { type: companyConstants.LIST_SUCCESS, data } }
    function failure(error) { return { type: companyConstants.LIST_FAILURE, error } }
}

<强> toastActions.js

import { toastConstants } from '../_constants';

export const toastActions = {
    success,
    error,
    clear
};

function success(message) {
    return { type: toastConstants.SUCCESS, message };
}

function error(message) {
    return { type: toastConstants.ERROR, message };
}

function clear() {
    return { type: toastConstants.CLEAR };
}

<强> toastReducer.js

import { toastConstants } from '../_constants';

const initialState = {
    type: toastConstants.CLEAR,
    message: null
};

export function toast(state = initialState, action) {
  switch (action.type) {
    case toastConstants.SUCCESS:
      return {
        type: toastConstants.SUCCESS,
        message: action.message
      };
    case toastConstants.ERROR:
      return {
        type: toastConstants.ERROR,
        message: action.message
      };
    case toastConstants.CLEAR:
      return {};
    default:
      return initialState
  }
}

希望它对你有用! 欢呼声。

答案 1 :(得分:0)

因此问题并非特定于redux连接器功能。事实上,从事件处理程序抛出的所有错误都不会触发componentDidCatch。见https://reactjs.org/docs/error-boundaries.html#how-about-event-handlers

我不想使用一些redux错误状态来捕获这些错误,因为这需要更多的样板。例如:它会强制我将所有组件连接到redux以进行错误处理,即使对于不需要redux状态或不会更新状态的组件(错误状态除外)也是如此。不是想法解决方案,但为了解决这个问题,我为我的所有事件处理程序创建了一个单独的函数。

//componentEventHandler.js
export function handleEvent () {
  const args = Array.from(arguments);
  const fn = args.shift();
  fn(...args).catch(e => this.setState(() => { throw e }));
}

然后我在我的组件中导入此函数并使用如下。

onPress={handleEvent.bind(this, this.props.signIn, this.state.email, this.state.password)}

现在App.js的所有子组件都会将事件错误发送到App.js