【问题标题】:React Redux "Cannot read property 'status' of undefined" error when trying to access store variable尝试访问存储变量时,React Redux“无法读取未定义的属性'状态'”错误
【发布时间】:2020-05-07 10:25:50
【问题描述】:

我正在开发一个应用程序来自学 React 和 Redux,但在尝试访问已添加到商店的变量时遇到了问题。

我可以将数据添加到存储对象并使用 console.log 验证数据是否存在,但是当我尝试深入了解我想要访问的实际变量时,我收到一个错误:“TypeError: Cannot读取未定义的属性“状态”。

查看状态时,我可以看到状态存在: {"customerInfo":[],"loginInfo":[],"storeStatus":[{"status":false}]}

但随后尝试访问 state.storeStatus[0] 中的任何内容(例如:state.storeStatus[0].status)返回未定义的错误。

如果我想将它分配给一个新变量以在某些条件渲染中使用,我应该尝试以不同的方式访问该变量吗?

storeStatusReducers.js

import deepFreeze from 'deep-freeze'

const state = [];
const storeStatusReducer = (state = true, action) => {
    switch(action.type) {
      case 'STORE_STATUS_UPDATE':
        state = [];  
        return [...state, action.data]
      default:
      return state
    }
  }

 export const updateStoreStatusAction = (status) => {
    return {
      type: 'STORE_STATUS_UPDATE',
      data: {
        status
      }
    }
  }

  deepFreeze(state)
  export default storeStatusReducer;

home.js

import React,  { useState, useEffect } from "react";
import axios from "axios";
import { updateStoreStatusAction } from '../reducers/storeStatusReducers' 
import { useSelector, useDispatch } from 'react-redux'

const storeInfo = {
  storeId : "1337",
  storeStatus: true
}

const HomePage = (props) => {
  const dispatch = useDispatch()
  const storeStatusData = useSelector(state => state.storeStatus);

  let payload = {
    storeId: storeInfo.storeId,
  };
  useEffect(() => {
  axios({
    url: "/api/get-test-data/" + storeInfo.storeId,
    method: "GET",
    data: payload,
  })
    .then((data) => {
     console.log("data.data.storeStatusPayload", JSON.stringify(data.data.storeStatusPayload))
     updateStoreStatus(data.data.storeStatusPayload);
     
    })
    .catch((error) => {
      console.log("changeStoreStatus: Internal server error");
    });
  }, []);

  const updateStoreStatus = (updatedStoreStatus) => {
    dispatch(updateStoreStatusAction(updatedStoreStatus));
  };

  //This works and produces: {"status":false}
  console.log("storeStatusData", JSON.stringify(storeStatusData[0]))
  // This does not when trying to access status
  console.log("storeStatusData", JSON.stringify(storeStatusData[0].status))


  return (
    <div>
      <main>
      <h1>Test App</h1>

      </main>    
    </div>
  );
};

export default HomePage;

更新: 现在正在工作。谢谢!

更新了 home.js

import React,  { useState, useEffect } from "react";
import axios from "axios";
import { updateStoreStatusAction } from '../reducers/storeStatusReducers' 
import { useSelector, useDispatch } from 'react-redux'

const storeInfo = {
  storeId : "1337",
  storeStatus: true
}

const HomePage = (props) => {
  const dispatch = useDispatch()
  const storeStatusData = useSelector(state => state.storeStatus);

  let payload = {
    storeId: storeInfo.storeId,
  };
  useEffect(() => {
  axios({
    url: "/api/get-test-data/" + storeInfo.storeId,
    method: "GET",
    data: payload,
  })
    .then((data) => {
     console.log("data.data.storeStatusPayload", JSON.stringify(data.data.storeStatusPayload))
     updateStoreStatus(data.data.storeStatusPayload);
     
    })
    .catch((error) => {
      console.log("changeStoreStatus: Internal server error");
    });
  }, []);

  const updateStoreStatus = (updatedStoreStatus) => {
    dispatch(updateStoreStatusAction(updatedStoreStatus));
  };

  //This works and produces: {"status":false}
  console.log("storeStatusData", JSON.stringify(storeStatusData[0]))
  // This does not when trying to access status
  console.log("storeStatusData", JSON.stringify(storeStatusData[0].status))

  const renderLoadingBar = () => {
    if (storeStatusData[0] ) {
      return (
        <div>
          loaded
        </div>
      );
    } else {
      return (
        // table container
        <div>
        loading
         </div> 
      );
    }
  };

  return (
    <div>
      <main>
      <h1>Test App</h1>
<div>{renderLoadingBar()}</div>
      </main>    
    </div>
  );
};

export default HomePage;

【问题讨论】:

  • 初始状态是一个空数组,所以storeStatusData[0]undefined。它看起来与storeStatusData[0] 一起工作的原因是控制台稍后在您在控制台中检查它时评估该值(chrome 会这样做),或者它记录两次,一次作为undefined,一次作为对象。
  • 而且由于您使用的是JSON.stringify,我倾向于使用 2 条日志。

标签: javascript reactjs react-redux


【解决方案1】:

由于您的效果是异步运行的,因此您的数据在初始渲染时将不可用。这意味着尝试访问不存在的数组元素上的道具会导致您的应用崩溃。

您的初始日志语句似乎 起作用的事实很可能是因为它在初始渲染时是undefined,但在第二次渲染时是预期值。另一方面,您的第二个 console.log 语句会立即失败,并且您永远无法进行后续渲染。

为防止发生此问题,一种常见的模式是使用短路评估。例如:

const HomePage = (props) => {
  // (initial component code here)

  // Only log if the array element exists
  storeStatusData[0] && console.log("storeStatusData", JSON.stringify(storeStatusData[0].status))


  return (
    <div>
      <main>
      <h1>Test App</h1>

      </main>    
    </div>
  );
};

【讨论】:

  • 这很有意义,但是当我设置一些东西来测试它看起来数据被覆盖并且变得未定义时。我放了一个加载栏来显示 if (storeStatusData[0] ),否则显示一些文本。文本短暂显示,然后返回加载栏屏幕,告诉我 storeStatusData[0] 再次变为未定义。
  • 你能用你现在遇到的问题更新问题吗?了解正在发生的事情有点困难。
  • 这个问题已经用我在上面评论中提到的新代码进行了更新。
  • 看起来你的逻辑可能颠倒了?如果数组元素存在则应该加载它
  • 是的,你完全正确。我认为它现在按预期工作。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-10
  • 2019-02-15
  • 2018-06-03
  • 1970-01-01
  • 1970-01-01
  • 2017-06-22
  • 2021-01-15
相关资源
最近更新 更多