首页 > 解决方案 > 未定义不是对象 - 反应导航

问题描述

对不起,如果这很冗长,但我的 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[]。

标签: javascriptreact-nativereduxreact-redux

解决方案


问题出在你的减速机上,

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
    );

推荐阅读