javascript - 未定义不是对象 - 反应导航
问题描述
对不起,如果这很冗长,但我的 React Native 项目有一个相当复杂的错误,我只想解释一下。
我有两个屏幕,A 和 B。屏幕 A 执行 API 请求以获取交易列表。当您按下交易时,应用程序导航到屏幕 B,并执行另一个 API 请求以获取该交易的详细信息。但是,在此屏幕上,返回以下错误:
TypeError: undefined is not an object (evaluating 'transactionDetails.length')
错误本身对我来说很有意义,transactionDetails 对象是未定义的,尽管我不知道为什么。但是,为了克服这个问题,我尝试检查 transactionDetails 对象是否未定义,如果是,则跳过 .length 函数。但是,这会在导航到屏幕 B 时导致以下错误:
TypeError: undefined is not an object (evaluating 'transactions.length')
哪个在屏幕 A 上,所以我不知道为什么当屏幕 B 加载时该页面会重新渲染……如果这有任何意义的话。
如果我也执行在屏幕 B 上添加到屏幕 A 的相同检查,我可以摆脱该错误,然后我不会收到任何错误。但是,如果我从屏幕 A 导航到屏幕 B,然后按后退按钮,则屏幕 A 上的 API 数据不再存在,只能通过拉动刷新来检索。
注意:屏幕 A 和屏幕 B 在不同的地方执行 if 检查 - 我尝试将它们放在同一个地方,这不是导致错误的原因
抱歉,很长的解释,但我希望这是有道理的。以下是此应用程序的相关代码部分:
屏幕 A
const ScreenA = (props) => {
const [isLoading, setIsLoading] = useState();
const [error, setError] = useState();
const transactions = useSelector(
(state) => state.transactions.transactionsList
);
const dispatch = useDispatch();
const loadTransactions = useCallback(async () => {
setError(null);
setIsLoading(true);
try {
await dispatch(transactionActions.fetchTransactions(id));
} catch (err) {
setError(err.message);
}
setIsLoading(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
setIsLoading(true);
loadTransactions().then(() => {
setIsLoading(false);
});
}, [dispatch, loadTransactions]);
return (
{!isLoading && transactions.length === 0 ? (
// Error
) : (
// Screen Content
)}
);
}
屏幕 B
const ScreenB = (props) => {
const [isLoading, setIsLoading] = useState();
const [error, setError] = useState();
const transactionDetails = useSelector(
(state) => state.transactions.transactionDetails
);
const dispatch = useDispatch();
const loadTransactionDetails = useCallback(async () => {
setError(null);
setIsLoading(true);
try {
await dispatch(transactionActions.fetchTransactionDetails(id));
} catch (err) {
setError(err.message);
}
setIsLoading(false);
}, [dispatch, setIsLoading, setError]);
useEffect(() => {
setIsLoading(true);
loadTransactionDetails().then(() => {
setIsLoading(false);
});
}, [dispatch, loadTransactionDetails]);
/* THIS IS THE BREAKING LINE*/
if (!isLoading && transactionDetails.length === 0) {
// Error
}
return (
// Screen content
);
}
减速器
const initialState = {
transactionsList: [] as Transaction[],
transactionDetails: [] as TransactionDetails[]
};
export default (state = initialState, action) => {
switch (action.type) {
case TRANSACTIONS:
return {
transactionsList: action.transactions,
};
case TRANSACTION_DETAILS:
return {
transactionDetails: action.transactionDetails,
};
default:
return state;
}
};
调试信息 为了帮助调试,我尝试将 console.log 添加到屏幕 A 和 B,就在分别声明事务和 transactionDetails 之后,以记录它们的值。屏幕 A 在打印响应数据之前打印 array[] 几次,而屏幕 B 打印未定义。我认为这就是错误的原因,transactionDetails 为空时未定义,而不是 array[]。
解决方案
问题出在你的减速机上,
export default (state = initialState, action) => {
switch (action.type) {
case TRANSACTIONS:
// you need to spread the existing state
return { ...state, transactionsList: action.transactions};
case TRANSACTION_DETAILS:
return { ...state,transactionDetails: action.transactionDetails };
default:
return state;
}
};
当您发送类型的操作时,TRANSACTIONS
您只是返回
{
transactionsList: action.transactions,
};
因此,当您转到屏幕 B 时,transactions
商店中的状态将只有这个
{
// other piece of state
....
transactions: {
transactionsList: [....]
}
....
}
不会有transactionDetails
,所以下面的代码将返回该值undefined
。
const transactionDetails = useSelector(
(state) => state.transactions.transactionDetails
);
推荐阅读
- spring-boot - 具有多个数据源的春季批处理junit。spring data jpa无法将数据保存在内存数据库中
- java - 不兼容的类型:无法转换
- javascript - 在 HTML 中滚动期间,如何为单个页面网站中的每个“部分”添加不同的导航栏徽标?
- php - PHP文件未运行,权限问题
- kubernetes - OpenShift 或 Kubernetes - 使用 curl 命令从 CronJob 创建作业
- xml - Ansible xml 将值放在底部的新节点中,而不是修改现有节点
- php - 在 PHP 应用程序中获取“ORA-00979:不是 GROUP BY 表达式”
- r - R:如何在现有的 R 时间序列类中创建具有多个时间尺度的时间序列对象?
- java - AWS S3 Java SDK 是否支持 socks 代理?
- angular - Angular 表单在 Internet Explorer 11 中不起作用