THIS QUESTION IS ALREADY SOLVED. Scroll down or click here to view solutions
I am trying to use React to extract a JSON data from my server and render it with two functions. But it seems that the two render functions cannot read the values in the json correctly. I'm sure that my data server is working correctly.
Error log:
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)
App ponent:
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>
)
}
Question ponent:
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;
The JSON data:
{
"question": {
"title": "Question",
"create_by": "AZ",
"time": 1661394765044,
"detail": "<h4>info</h4>"
},
"answers": [
{
"create_by": "baa",
"time": 1661394765044,
"detail": "<h4>abc</h4>"
}
]
}
THIS QUESTION IS ALREADY SOLVED. Scroll down or click here to view solutions
I am trying to use React to extract a JSON data from my server and render it with two functions. But it seems that the two render functions cannot read the values in the json correctly. I'm sure that my data server is working correctly.
Error log:
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)
App ponent:
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>
)
}
Question ponent:
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;
The JSON data:
{
"question": {
"title": "Question",
"create_by": "AZ",
"time": 1661394765044,
"detail": "<h4>info</h4>"
},
"answers": [
{
"create_by": "baa",
"time": 1661394765044,
"detail": "<h4>abc</h4>"
}
]
}
Share
Improve this question
edited Aug 29, 2022 at 9:17
Arthur Zhou
asked Aug 25, 2022 at 23:45
Arthur ZhouArthur Zhou
531 gold badge2 silver badges4 bronze badges
5
- Hi Arthur, did you try out the answer I pasted. – Youssouf Oumar Commented Aug 27, 2022 at 8:45
- ofcourse, and there's still some error. And im checking my backend. – Arthur Zhou Commented Aug 27, 2022 at 10:27
- A different one? – Youssouf Oumar Commented Aug 27, 2022 at 10:29
- thanks, but im planning to use other js. Because even the example from their official doc went wrong. Thanks for your answers :) – Arthur Zhou Commented Aug 27, 2022 at 10:32
- Hi Arthur, you should be pasting an answer instead of editing the question itself. It's how QA should be here in Stack Overflow :) – Youssouf Oumar Commented Aug 28, 2022 at 18:38
3 Answers
Reset to default 0I think they are not pure functions, they are ponents, you cannot share global variables and that is not the way to pass data between ponents in React, the way to do it correctly is using a context or props, to pass through props I leave you an example of the following way, you should apply this in the other variables too, example:
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;
First, in App
remove JSON.parse(resJson)
as it's already parsed by res.json()
. Use some loader while fetching the data as it happens asynchronously, and your ponent render first. For that give nothing to useState
as parameter so item
is undefined
at the beginning.
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>
)
}
Second, you shouldn't be using global variables to render data in your ponents when using React, instead use props
and state
. To do so, change Question
ponent so it receives the data it needs as props
and notice it's passed in App
to it:
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>
)
}
EDIT: I finally solved this problem. Hope it will help you.
There are several problems on frontend and backend.
Frontend:
- I use
useState
anduseEffect
to hendle fetched data. This is my code:
const [item, setItems] = useState()
useEffect(() => {
fetch('http://localhost:61780/')
.then((res) => res.json())
.then((data) => {
setItems(data)
})
}, []);
- While reading the json data, do like this:
<level 1>?.<level 2>?.<level 3>
.
DON'T DO THIS: <level 1>.<level 2>.<level 3>
. This will throw out an exception: Cannot read ... from type 'undefined'
Example code:
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 data:
{
"question": {
"title": "Question",
"create_by": "AZ",
"time": 1661394765044,
"detail": "<h4>info</h4>"
},
"answers": [
{
"create_by": "baa",
"time": 1661394765044,
"detail": "<h4>abc</h4>"
}
]
}
Backend:
- You need to add a header in your server responce:
Access-Control-Allow-Origin
, and it's value is your api url(or you can use*
if your api is a public one) It's like this:Access-Control-Allow-Origin: <url or *>
If you don't do this, it will throw out an exception: CORS header 'Access-Control-Allow-Origin' missing
. I'm not sure if other js is like this.