我想了解使用React-Redux进行错误处理的更通用或更正确的方法。
假设我有电话号码注册组件。
如果输入的电话号码无效,该组件将引发错误提示
处理该错误的最佳方法是什么?
想法1: 创建一个组件,该组件接受错误并在将错误传递给它时调度一个操作
想法2: 由于错误与该组件相关,请将错误传递给组件(该组件未连接到redux,即错误处理程序组件将不会分派操作)
问题:有人可以指导我在React-Redux中针对大型应用程序进行错误处理的正确方法吗?
我想了解使用React-Redux进行错误处理的更通用或更正确的方法。
假设我有电话号码注册组件。
如果输入的电话号码无效,该组件将引发错误提示
处理该错误的最佳方法是什么?
想法1: 创建一个组件,该组件接受错误并在将错误传递给它时调度一个操作
想法2: 由于错误与该组件相关,请将错误传递给组件(该组件未连接到redux,即错误处理程序组件将不会分派操作)
问题:有人可以指导我在React-Redux中针对大型应用程序进行错误处理的正确方法吗?
Answers:
我想说的是,您的最初想法都无法抓住整个情况。想法1只是回调。如果要使用回调:useCallback
。如果您不需要使用redux,则创意2会起作用,并且更可取。有时您最好使用redux。也许您通过检查输入字段中是否没有错误或类似内容来设置表单有效性。由于我们是关于redux的主题,因此我们假设情况就是如此。
通常,使用redux进行错误处理的最佳方法是使一个错误字段处于状态,然后将其传递给错误组件。
const ExampleErrorComponent= () => {
const error = useSelector(selectError);
if (!error) return null;
return <div className="error-message">{error}</div>;
}
错误组件不仅可以显示错误,还可以通过产生副作用useEffect
。
错误的设置/取消方式取决于您的应用程序。让我们使用您的电话号码示例。
然后,您将根据电话号码更改操作设置或取消设置错误字段。在使用switch语句构建的reducer中,它可能看起来像这样。
case 'PHONE_NUMBER_CHANGE':
return {
...state,
phoneNumber: action.phoneNumber,
error: isValidPhoneNumber(action.phoneNumber) ? undefined : 'Invalid phone number',
};
假设您要将电话号码发送到进行验证的后端,然后再对该号码进行操作。您不知道数据在客户端是否有效。您只需要听服务器的话就可以了。
const handleSubmit = useCallback(
() => sendPhoneNumber(phoneNumber)
.then(response => dispatch({
type: 'PHONE_NUMBER_SUBMISSION_SUCCESS',
response,
}))
.catch(error => dispatch({
type: 'PHONE_NUMBER_SUBMISSION_FAILURE',
error,
})),
[dispatch, phoneNumber],
);
然后,减速器应为错误提供适当的消息并进行设置。
不要忘记取消错误。您可以根据更改应用程序或在发出其他请求时取消错误。
我概述的两种方法并不互相排斥。您可以使用第一个显示本地可检测到的错误,也可以使用第二个显示服务器端或网络错误。
我会使用带有yup验证的formik。然后,对于服务器端错误,我将使用以下内容:
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Spinner } from "@blueprintjs/core";
export default ({ action, selector, component, errorComponent }) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(action());
}, [dispatch, action]);
const DispatchFetch = () => {
const { data, isRequesting, error } = useSelector(selector());
if (!isRequesting && data) {
const Comp = component;
return <Comp data={data}></Comp>;
} else if (error) {
if (errorComponent) {
const ErrorComp = errorComponent;
return <ErrorComp error={error}></ErrorComp>;
}
return <div>{error}</div>;
}
return <Spinner></Spinner>;
};
return <DispatchFetch></DispatchFetch>;
};
这取决于您在谈论哪种错误处理。如果仅是表单验证处理,那么我认为您不需要Redux-请阅读本文。如果您的错误只会在该组件中“消耗”,为什么将其发送到redux?您可以轻松地使用本地状态。
另一方面,如果您想向用户显示某种错误通知以指示站点上的任何HTTP调用是否失败,则可以通过从应用程序所有部分(甚至通常是中间件)分发错误来使Redux受益
dispatch({ type: 'SET_ERROR_MESSAGE', error: yourErrorOrMessage });
// simple error message reducer
function errorMessage(state = null, action) {
const { type, error } = action;
switch (type) {
case 'RESET_ERROR_MESSAGE':
return null;
case 'SET_ERROR_MESSAGE':
return error;
}
return state
}
您需要定义状态的组织方式,以及需要将某些状态放入redux还是仅将其保持在组件的本地状态。您可以将所有内容放到redux中,但是我个人认为这是一个过大的杀伤力-如果仅组件Y关心状态X,为什么要在组件Y中放置状态X?如果您正确地构造代码,则以后由于某种原因应用程序的其他部分开始依赖该状态时,将该状态从本地移动到redux不会有问题。
我这样想,应该是什么状态?从国家应该得到什么呢?状态应存储在redux中,并应计算导数。
电话号码是状态,该字段具有焦点的是状态,但是它是否有效,可以从状态值中得出。
我将使用Reselect来缓存派生并在未修改相关状态时返回相同的结果。
export const showInvalidPhoneNumberMessage = createSelector(
getPhoneValue,
getFocusedField,
(val, focus) => focus !== 'phone' && val.length < 10 // add other validations.
)
然后,您可以在所有可能关心此值的组件中的mapStateToProps中使用选择器,也可以在异步操作中使用它。如果焦点没有改变,或者字段的值没有改变,则不会进行任何重新计算,而是返回先前的值。
我添加选定的状态检查只是为了显示如何将多个状态组合在一起以得出一个推导。
我个人尝试通过保持状态尽可能小来处理问题。例如,假设您要创建自己的日历。您是将州中的每一天存储起来,还是只需要知道几件事,例如当前正在查看的当前年和月。只需使用这两种状态,您就可以计算要显示在日历上的日期,而无需重新计算直到其中之一发生更改,并且这种重新计算实际上是自动进行的,无需考虑所有可能的方法。更改。