React / Redux - 无法读取未定义的属性“XXX”

Posted

技术标签:

【中文标题】React / Redux - 无法读取未定义的属性“XXX”【英文标题】:React / Redux - Cannot read property "XXX" of undefined 【发布时间】:2017-09-05 13:00:41 【问题描述】:

这是我已经坚持了两个多星期的事情,所以这个问题是我解决这个问题的最后机会。我希望任何人都可以帮助我(因为问题很可能是一些小问题/我错过了)


使用 Node、Redux 和 React,我从我的 Mongo 数据库返回一个集合。 我正在使用 react-redux "connect" 从我的商店中检索我的数据如下面的 JSX 所示。

JSX:

import React from "react";
import connect from "react-redux"
import fetchArticle from "../../actions/articleActions"
var classNames = require('classnames');
import GlobalHero from '../modules/GlobalHero.jsx';

@connect((store) => 
    return article: store.article.article, fetching: store.article.fetching;
)

export default class Article extends React.Component 

    // BEFORE COMPONENT RENDER (For Everyhing else)
    constructor() 
        super();
        //sets initial state
        this.state = 
            page: "Article"
        ;
    

    // BEFORE COMPONENT RENDER (For Ajax / Dispatcher Events): get article Title / Thumbnail rows based on this.props.indexLimit
    componentWillMount = () => 
        console.log(this.props)
        this.props.dispatch(fetchArticle(this.props.params.id))
    

    // ON COMPONENT RENDER
    componentDidMount = () => 

    render() 

        if (this.props.fetching) 
            return (
                <p>Loading...</p>
            );
         else 
            return (
                <div>
                    <h1>this.props.article.title</h1>
                    <h2>this.props.article.subTitle</h2>

                </div>
            );
        
    

我的问题:

所以当我在我的 JSX 中返回“title”和“subTitle”时,它会完美地完成所有事情(见下文):

  <h1>this.props.article.title</h1>
  <h2>this.props.article.subTitle</h2>

数据也显示在我的屏幕上(见下文):

但是...只要我添加:

  <h3>this.props.article.body.section1.text</h3>

我的页面无法加载,我的控制台返回:

无法读取未定义的属性“section1”

当我在控制台中查看返回数据的状态时:

如您所见,它在控制台中返回“section1”,所以我在 JSX 中一定是错误地调用了“section1”?

我认为问题可能与“section1”嵌套在我的 mongo db 集合中比“title”或“subTitle”更深这一事实有关。

下面我将向您展示我在此页面上的其余路线 - 我在网上无休止地查找,无法查明我的问题。

行动:

import axios from "axios";
//var resourceUrl = "http://localhost:7777/api/schools";

export function fetchArticle(id) 

    return function(dispatch) 
        dispatch(
            type: "FETCH_ARTICLE"
        )
        axios.get('/api/article', 
                params: 
                    id: id
                
            )
            .then((response) => 
                dispatch(
                    type: "FETCH_ARTICLE_FULFILLED",
                    payload: response.data
                )
            )
            .catch((err) => 
                dispatch(
                    type: "FETCH_ARTICLE_REJECTED",
                    payload: err
                )
            )
    

减速机:

export default function reducer(state = 
    article: [],
    fetching: false,
    fetched: false,
    error: null,
, action) 

    switch (action.type) 
        case "FETCH_ARTICLE":
            
                return 
                    ...state,
                    fetching: true
                
            
        case "FETCH_ARTICLE_REJECTED":
            
                return 
                    ...state,
                    fetching: false,
                    error: action.payload
                
            
        case "FETCH_ARTICLE_FULFILLED":
            
                return 
                    ...state,
                    fetching: false,
                    fetched: true,
                    article: action.payload,
                
            
    
    return state

商店:

import 
    applyMiddleware,
    createStore
 from "redux"

import logger from "redux-logger"
import thunk from "redux-thunk"
import promise from "redux-promise-middleware"

import reducer from "./reducers"

const middleware = applyMiddleware(promise(), thunk, logger())

export default createStore(reducer, middleware)

节点/快速调用:

app.get('/api/article', (req, res) => 

    var ObjectId = require('mongodb').ObjectID;
    var articles;

    db.collection('articles')
        .findOne(
            "_id": ObjectId("58c2a5bdf36d281631b3714a")
        )
        .then(result => 
            articles = result;
        ).then(() => 
            res.send(articles);
        ).catch(e => 
            console.error(e);
        );

);

我的 mongo DB 集合中的记录:


    "_id": 
        "$oid": "58c2a5bdf36d281631b3714a"
    ,
    "title": "EntertheBadJah",
    "subTitle": "Lorem ipsum dolor",
    "thmbNailImg": "",
    "headerImg": "",
    "body": 
        "section1": 
            "include": true,
            "text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
        ,
        "section2": 
            "include": true,
            "text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
        ,
        "bodyImg": 
            "include": true,
            "img": ""
        ,
        "section3": 
            "include": true,
            "text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
        
    ,
    "links": 
        "recourse": 
            "include": false,
            "text": "Go watch their interview",
            "link": ""
        ,
        "soundcloud": 
            "include": true,
            "link": "www.soundcloud.com/BadJah"
        ,
        "spotify": 
            "include": false,
            "link": ""
        ,
        "youtube": 
            "include": false,
            "link": ""
        ,
        "twitter": 
            "include": false,
            "link": ""
        ,
        "facebook": 
            "include": false,
            "link": ""
        ,
        "instagram": 
            "include": false,
            "link": ""
        
    ,
    "keywords": "Badjah",
    "date": "",
    "author": "Aagentah",
    "dateAdded": "2017-06-01T00:00:00.000Z"


感谢您对此问题的任何帮助或建议 - 在此先感谢您。

【问题讨论】:

@barbsan - 我不这么认为,因为“section1”在“body”内部。 查看这个问题的底部 sn-p:title 和 subTitle 是 section1 @barbsan 上方的一层 我对 react 和 redux 一无所知。但这似乎很可怕,类似于我在 Angular2 中学习 RxJS 时遇到的问题。在那里,我可以使用一种叫做“猫王操作员”的东西。例如:this.props.article.body?.section1.text 将处理异步加载的项目(看起来第 1 节几乎是以这种方式加载的) 如果该对象与上面显示的对象等价,那么您似乎正确地调用了它。如果您在组件渲染中调试 this.props.article.body,它是否提供未定义? 在我的控制台中,section1 有数据@KornholioBeavis 【参考方案1】:

React 将在其 props(通过 Redux connect 提供)更改时重新呈现页面。由于您只是触发获取componentWillMount 中数据的请求,因此根据定义,这不会在第一次渲染时完成。但是,在第一种情况下这没有问题,因为this.props.article 保证是一个对象[],所以this.props.article.title 将只是undefined。一旦对 API 的请求返回,article 就会在商店中更新,并且页面会以预期的内容呈现。

但是,由于this.props.article 最初是[],如果您尝试渲染this.props.article.body.section1.text,您的代码将抛出异常,因为article 是一个对象,article.bodyundefined。已经抛出错误,当文章在商店中实际更新时,组件将无法重新呈现。

在尝试呈现子键之前,您需要添加一个保护来检查this.props.article 的形状,或者在请求与实际文章一起返回之前,为存储添加一个更完整的默认值。

【讨论】:

啊,我明白了,我应该如何在我的代码中添加这个守卫? 上述答案中的一个例子。 啊,好吧,检查我的整篇文章而不是只检查一个对象有什么好的做法,因为理想情况下我不希望每个属性都有一个检查函数,或者我会吗? 我对选择器有类似的问题。在我的情况下,组件会被 UI 渲染,因为第二次重新渲染发生得很快,但在控制台中我有上面提到的错误。为了测试一个问题,我写了这个“守卫”:modules: this.isApplicationsFetching &amp;&amp; this.isModulesFetching ? `` : moduleSelectors.selectModulesByApplicationId(state, applicationId: this.appid ), ,这向我证明了选择器在第一次渲染时无法通过appid 选择任何东西。我仍在寻找正确的解决方案,但会在此处留下此评论。【参考方案2】:

试试这样的。可能是在第一个渲染周期中它还没有出现。

checkRender()
      typeof this.props.article.body === 'undefined' 
      ? return null 
      : return this.props.article.body.section1.text
    

然后使用它::>

<h3>checkRender</h3>

【讨论】:

啊,好吧,检查我的整篇文章而不是只检查一个对象有什么好的做法,因为理想情况下我不希望每个属性都有一个检查函数,或者我会吗? 你可以创建一个 HOC 来检查所有的 props,然后将它包裹在你的组件周围。【参考方案3】:

我绝对可以推荐将流类型检查添加到您的代码库 (http://flow.org)。它可以逐个文件添加,但对调试这类问题有很大帮助。

【讨论】:

以上是关于React / Redux - 无法读取未定义的属性“XXX”的主要内容,如果未能解决你的问题,请参考以下文章

无法使用React redux读取未定义的地图属性

我在 react-redux 小测试中得到“无法读取未定义的属性 'cart'”

React Redux TypeError:无法读取未定义的属性“地图”

React Redux:无法读取未定义的属性“调度”

Redux 和 React-Native:无法读取未定义的属性“类型”

React-Redux:Uncaught TypeError:无法读取未定义的属性“name”