开发者问题收集

React:未捕获的 TypeError:无法读取未定义的属性

2022-08-25
21673

此问题已解决。向下滚动或 单击此处 查看解决方案

我尝试使用 React 从我的服务器提取 JSON 数据并使用两个函数渲染它。但似乎两个渲染函数无法正确读取 json 中的值。 我确定我的数据服务器正常工作。

错误日志:

Unhandled Runtime Error
Uncaught TypeError: Cannot read properties of undefined (reading 'title')

Source
http://localhost:8080/dist/App.js [:19:68]
TypeError: Cannot read properties of undefined (reading 'title')
    at Question (http://localhost:8080/dist/App.js:19:68)
    at renderWithHooks (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:16313:18)
    at mountIndeterminateComponent (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:20077:13)
    at beginWork (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:21590:16)
    at beginWork$1 (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:27414:14)
    at performUnitOfWork (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:26548:12)
    at workLoopSync (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:26454:5)
    at renderRootSync (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:26422:7)
    at performSyncWorkOnRoot (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:26074:20)
    at flushSyncCallbacks (http://localhost:8080/_snowpack/pkg/react-dom.v18.2.0.js:12050:22)

应用组件:

let prop

function App() {
    const [item, setItems] = useState([])

    useEffect(() => {
        fetch('http://localhost:9090/')
            .then((res) => res.json())
            .then((resJson) => {
                const data = JSON.parse(resJson)
                setItems(data)
            })
    }, [])
    prop = item
    return (
        <div>
            <Question/>
            <hr/>
        </div>
    )
}

问题组件:

function Question() {
    return (
        <div className={"question"}>
            <h1>{ prop.question.title }</h1>
            <p className={"info"}>Created by user: { prop.question.create_by }</p><br/>
            <p className={"info"}>On { Intl.DateTimeFormat('en-US', {year: 'numeric', month: '2-digit',day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(new Date(prop.question.time)) }</p><br/>
            <hr/>
            <div dangerouslySetInnerHTML={{__html: prop.question.detail}}></div>
        </div>
    )
}

export default App;

JSON 数据:

{
  "question": {
    "title": "Question",
    "create_by": "AZ",
    "time": 1661394765044,
    "detail": "<h4>info</h4>"
  },
  "answers": [
    {
      "create_by": "baa",
      "time": 1661394765044,
      "detail": "<h4>abc</h4>"
    }
  ]
}
3个回答

我认为它们不是纯函数,它们是组件,你不能共享全局变量,这不是在 React 中在组件之间传递数据的方式,正确的方法是使用上下文或 props,通过 props 传递数据我给你留下了以下方式的示例,你也应该在其他变量中应用它,例如:

function App() {
    const [item, setItems] = useState([])

    useEffect(() => {
        fetch('http://localhost:9090/')
            .then((res) => res.json())
            .then((resJson) => {
                const data = JSON.parse(resJson)
                setItems(data)
            })
    }, [])

    return (
        <div>
            <Question title={item.question.title}/>
            <hr/>
        </div>
    )
}

function Question({title}) {
    return (
        <div className={"question"}>
            <h1>{ title }</h1>
            <p className={"info"}>Created by user: { prop.question.create_by }</p><br/>
            <p className={"info"}>On { Intl.DateTimeFormat('en-US', {year: 'numeric', month: '2-digit',day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(new Date(prop.question.time)) }</p><br/>
            <hr/>
            <div dangerouslySetInnerHTML={{__html: prop.question.detail}}></div>
        </div>
    )
}

export default App;
CoolLife
2022-08-26

首先,在 App 中删除 JSON.parse(resJson) ,因为它已被 res.json() 解析。在获取数据时使用一些加载器,因为它是异步发生的,并且您的组件首先呈现。为此,不要将任何内容提供给 useState 作为参数,因此 item 在开头是 undefined

function App() {
    const [item, setItems] = useState()

    useEffect(() => {
        fetch('http://localhost:9090/')
            .then((res) => res.json())
            .then((data) => {
                setItems(data)
            })
    }, []);

    if(!item) return <p>Fetching data...</p>

    return (
        <div>
            <Question question = {item.question}/>
            <hr/>
        </div>
    )
}

其次,使用 React 时,您不应该使用全局变量在组件中呈现数据,而是使用 propsstate 。为此,更改 Question 组件,使其接收所需的数据作为 props ,并注意它在 App 中传递给它:

function Question(props) {
    return (
        <div className={"question"}>
            <h1>{ props.question.title }</h1>
            <p className={"info"}>Created by user: { props.question.create_by }</p><br/>
            <p className={"info"}>On { Intl.DateTimeFormat('en-US', {year: 'numeric', month: '2-digit',day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(new Date(props.question.time)) }</p><br/>
            <hr/>
            <div dangerouslySetInnerHTML={{__html: props.question.detail}}></div>
        </div>
    )
}
Youssouf Oumar
2022-08-26

编辑:我终于解决了这个问题。希望它能帮助你。

前端和后端都存在一些问题。

前端:

  1. 我使用 useStateuseEffect 来处理获取的数据。 这是我的代码:
const [item, setItems] = useState()

    useEffect(() => {
        fetch('http://localhost:61780/')
            .then((res) => res.json())
            .then((data) => {
                setItems(data)
            })
    }, []);
  1. 在读取 json 数据时,请执行以下操作: <level 1>?.<level 2>?.<level 3>

不要这样做: <level 1>.<level 2>.<level 3> 。这会抛出一个异常: Cannot read ... from type 'undefined'

示例代码:

import React, {useEffect, useState} from 'react';
import './extraUI.css'


function App() {
    const [item, setItems] = useState()

    useEffect(() => {
        fetch('http://localhost:61780/')
            .then((res) => res.json())
            .then((data) => {
                setItems(data)
            })
    }, []);
    console.warn(item)

    return (
        <>
            <Question props={item}/>
            <hr/>
            <Answer props={item}/>
        </>
    )
}

function Question({props}) {
    return (
        <div className={"question"}>
            <h1>{ props?.question?.title }</h1>
            <p className={"info"}>Created by user: { props?.question?.create_by }</p><br/>
            <p className={"info"}>On { }</p><br/>
            <hr/>
            <div dangerouslySetInnerHTML={{__html: props?.question?.detail}}></div>
        </div>
    )
}

function Answer({props}) {
    return (
        props?.answers?.map((answer) => {
            return (
                <div className={"answer"}>
                    <h4 className={"info"}>Answer by: { answer?.create_by }</h4><br/>
                    <p className={"info"}>On { Intl.DateTimeFormat('en-US', {year: 'numeric', month: '2-digit',day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'}).format(new Date(answer?.time)) }</p><br/>
                    <hr/>
                    <div dangerouslySetInnerHTML={{__html: answer?.detail}}></div>
                </div>
            )
        })
    )
}

export default App;

Json数据:

{
  "question": {
    "title": "Question",
    "create_by": "AZ",
    "time": 1661394765044,
    "detail": "<h4>info</h4>"
  },
  "answers": [
    {
      "create_by": "baa",
      "time": 1661394765044,
      "detail": "<h4>abc</h4>"
    }
  ]
}

Backend:

  1. 你需要在服务器响应中添加一个header: Access-Control-Allow-Origin ,它的值是你的api url(或者如果你的api是公共的,你可以使用 * ) 就像这样: Access-Control-Allow-Origin: <url or *>

如果你不这样做,它会抛出一个异常: CORS header 'Access-Control-Allow-Origin' missing 。我不确定其他js是否是这样的。

Arthur Zhou
2022-08-29