【问题标题】:Redux state's nested object is available but unaccessible within componentRedux 状态的嵌套对象在组件内可用但不可访问
【发布时间】:2020-06-12 08:27:50
【问题描述】:

在此处输入代码我正在通过我的 app.js 文件中的 Provider 包装器为我的整个 React 应用程序提供 Redux 全局状态。

访问“当前配置文件”以外的任何其他状态都没有问题。

这是组件

import React, { Fragment, useEffect } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";

import { loadTargetProfiles, loadCurrentProfile  } from "../../actions/profile";

const Friends = ({
  loadCurrentProfile,
  loadTargetProfiles,
  profile: { currentProfile, targetProfiles, targetProfilesAreLoading },
}) => {
  useEffect(() => {
    loadTargetProfiles();
    loadCurrentProfile();
  }, []);

  console.log(currentProfile);

  return (
     ...
};

Friends.propTypes = {
  loadTargetProfiles: PropTypes.func.isRequired,
  loadCurrentProfile: PropTypes.func.isRequired,
  profile: PropTypes.object.isRequired,
};

const mapStateToProps = (state) => ({
  profile: state.profile,
});

export default connect(mapStateToProps, {
  loadCurrentProfile,
  loadTargetProfiles,
})(Friends);

这里是 loadCurrentProfile action,负责提供 currentProfile 状态。

export const loadCurrentProfile = () => async (dispatch) => {
  try {
    const res = await api.get("/profile/current");

    dispatch({
      type: LOAD_CURRENT_PROFILE,
      payload: res.data,
    });
  } catch (err) {
    dispatch({
      type: PROFILE_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status },
    });
  }
};

这里是 Reducer

的相关部分
const initialState = {
  currentProfile: null,
  targetProfile: null,
  targetProfiles: [],
  currentProfileIsLoading: true,
  targetProfileIsLoading: true,
  targetProfilesAreLoading: true,
  error: {},
};

//
// Export Reducer
export default function (state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case LOAD_CURRENT_PROFILE:
      return {
        ...state,
        currentProfile: payload,
        currentProfileIsLoading: false,
      };

这里是受到攻击的 API

router.get("/current", auth, async (req, res) => {
  try {
    const profile = await Profile.findOne({
      user: req.user.id,
    }).populate("user", ["_id", "username", "registerdate"]);

    if (!profile) {
      return res
        .status(400)
        .json({ msg: "There is no profile for this user." });
    }

    res.json(profile);
  } catch (err) {
    console.error(err.message);
    res.status(500).send("Server Error...");
  }
});

这是控制台

这里是展开的当前配置文件:

当我尝试进入 currentProfile 状态时,例如

  const Friends = ({
  loadCurrentProfile,
  loadTargetProfiles,
  profile: { currentProfile: {
    avatar
  }, targetProfiles, targetProfilesAreLoading },
}) => {
  useEffect(() => {
    loadTargetProfiles();
    loadCurrentProfile();
  }, []);

  console.log(avatar);

它给了我错误:

TypeError: Cannot read property 'avatar' of null

这里是 Redux 开发工具截图:

修复:

我(暂时)通过在声明函数后访问内部状态来消除错误。

const Friends= ({
  profile: { currentProfileIsLoading },
  currentProfile,
}) => {
  currentProfile && console.log(currentProfile.avatar);

它现在可以工作,但它肯定不是最优雅的解决方案。有没有办法在函数声明中添加这个守卫以便在一个地方设置状态?

【问题讨论】:

  • 你在使用 redux thunk 中间件吗? github.com/gaearon/redux-thunk
  • Friends 中第 26 行的日志似乎正在记录 currentProfile 每次状态更新并更新映射的属性。问题是什么? targetProfilestargetProfilesAreLoading 都是您所在州的真实值,但在 GET 解决之前,currentProfile 为 null。这不是您所期望的吗?
  • @Accretence 似乎您正试图在 mapStateToProps 中访问 state.profile,而您已在减速器中将其声明为 currentProfile
  • "state" 不为空,只有 currentProfile 为空。这些其他组件是否访问 this 相同的状态并按预期工作?
  • 是的,请参考我最初关于 currentProfile 为 null 的评论,直到获取解决,而其他两个属性 已定义。您无法访问 null 的X。更新了我的答案,以更加公开地指出这一点。

标签: reactjs redux react-redux


【解决方案1】:

问题:targetProfilestargetProfilesAreLoading 在您的状态下都是真值,但在 GET 解决之前,currentProfile 为空。您无法访问空对象的avatar 属性。

您可以为profile 提供一些默认参数值,这只有在profile 未定义时才真正有效,null 算作已定义值。

const Friends = ({
  loadCurrentProfile,
  loadTargetProfiles,
  profile: {
    currentProfile = {},
    targetProfiles,
    targetProfilesAreLoading
  },
}) => {
  useEffect(() => {
    loadTargetProfiles();
    loadCurrentProfile();
  }, []);

  console.log(currentProfile);

  return (
     ...
};

您还可以对可能未定义/为空的对象使用保护

currentProfile && currentProfile.avatar

另一种选择是使用像reselect 这样的状态选择器库,它允许您拉/增加/导出/等等...状态值作为道具传递。这也允许您为状态设置默认/备用值。它与 redux 搭配得很好。

【讨论】:

  • 感谢您的彻底回答,我设法通过临时解决方案摆脱了错误并更新了问题。
猜你喜欢
  • 1970-01-01
  • 2021-05-23
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2020-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多