无法读取未定义的 属性 ...(来自上下文的 property/value)
Cannot read property ... of undefined (property/value from context)
我从 UserDetails.js 收到错误“无法读取未定义的 属性 'name'”。该“名称”值来自上下文。
这是我的代码,
UsersContext.js:
import React, { createContext, useState, useEffect } from 'react'
import Axios from 'axios';
export const UserContext = createContext()
export function UserProvider(props) {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
useEffect(() => {
const getNews = async () => {
setLoading(true);
try {
const req = await Axios.get(`https://jsonplaceholder.typicode.com/users`);
const data = req.data;
setUsers(c => {
return [
...data
]
})
if(data.status !== "ok") throw new Error('error from api server');
} catch (error) {
setError(true)
}
setLoading(false);
}
getNews();
}, [])
return (
<UserContext.Provider value={{users, loading, error}}>
{props.children}
</UserContext.Provider>
)
}
UserDetails.js:
import React, { useContext } from 'react'
import { UserContext } from '../contexts/UsersContext'
function UserDetails(props) {
const {users} = useContext(UserContext)
return (
<div className="card">
<div className="card-header">
{users[0].name}
</div>
</div>
)
}
export default UserDetails
UserDetail 中的 {users[0].name} 未定义,但是当我尝试使用 {JSON.stringify(users[0])} 时,它的值是:
{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere@april.biz","address":{"street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{"lat":"-37.3159","lng":"81.1496"}},"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{"name":"Romaguera-Crona","catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets"}}
但是为什么,当使用 JSON.stringify 时有一个值,但是没有 JSON.stringify 就没有值(未定义)?
因为请求还没有return结果,用户还在[],
因此,要解决问题,您应该执行以下操作:
return loading? null : (
<div className="card">
<div className="card-header">
{users[0].name}
</div>
</div>
)
这是因为 useEffect 挂钩中的请求是异步的,并且 return 在第一次渲染时没有任何值。所以 users 有初始值 [] .
在显示 users 值之前,您可以使用可选链接或检查加载状态。
return (
<div className="card">
<div className="card-header">
{users[0]?.name}
</div>
</div>
)
或:
return loading ? null : (
<div className="card">
<div className="card-header">
{users[0]?.name}
</div>
</div>
)
还可以更好地处理 name 属性 是空字符串的情况,使用 || 运算符:
return loading ? null : (
<div className="card">
<div className="card-header">
{users[0]?.name || "Anonymous"}
</div>
</div>
)
在 apiRequest
到 return 所需的 3 秒内,您的 Javascript 代码正在尝试尽快编译。
如果您不考虑 readUsers
为 undefined
的 3 秒,您将收到错误消息。
这是因为 readUsers
被初始化为特殊值 undefined
,它没有可访问的方法或值。
如果您打开控制台并尝试输入 undefined[0]
或 undefined.toString()
,您将收到错误消息,因为 undefined
.
上不存在任何内容
为避免错误,您应该提供回退,因此当一个值是 undefined
时执行此操作,然后一旦它变成一个不同的值,该值具有可从中访问的方法和值,就允许它们执行。
import React, { useEffect, useState } from "react";
const oneSecond = 1000;
const threeSeconds = 3 * oneSecond;
// -> Fake API request
function apiRequest() {
// -> Create a new Promise
return new Promise((resolve) =>
// -> Resolve the Promise after waiting three seconds
setTimeout(() => resolve([{ name: "Bill" }]), threeSeconds)
);
}
export default function App() {
const [readUsers, writeUsers] = useState();
useEffect(() => {
// -> Make request (which takes 3 seconds), then update state
apiRequest().then((users) => writeUsers(users));
});
return (
<div>
{readUsers ? (
readUsers.map((user) => <div>{user.name}</div>)
) : (
<div>Loading...</div>
)}
</div>
);
}
我从 UserDetails.js 收到错误“无法读取未定义的 属性 'name'”。该“名称”值来自上下文。
这是我的代码,
UsersContext.js:
import React, { createContext, useState, useEffect } from 'react'
import Axios from 'axios';
export const UserContext = createContext()
export function UserProvider(props) {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
useEffect(() => {
const getNews = async () => {
setLoading(true);
try {
const req = await Axios.get(`https://jsonplaceholder.typicode.com/users`);
const data = req.data;
setUsers(c => {
return [
...data
]
})
if(data.status !== "ok") throw new Error('error from api server');
} catch (error) {
setError(true)
}
setLoading(false);
}
getNews();
}, [])
return (
<UserContext.Provider value={{users, loading, error}}>
{props.children}
</UserContext.Provider>
)
}
UserDetails.js:
import React, { useContext } from 'react'
import { UserContext } from '../contexts/UsersContext'
function UserDetails(props) {
const {users} = useContext(UserContext)
return (
<div className="card">
<div className="card-header">
{users[0].name}
</div>
</div>
)
}
export default UserDetails
UserDetail 中的 {users[0].name} 未定义,但是当我尝试使用 {JSON.stringify(users[0])} 时,它的值是:
{"id":1,"name":"Leanne Graham","username":"Bret","email":"Sincere@april.biz","address":{"street":"Kulas Light","suite":"Apt. 556","city":"Gwenborough","zipcode":"92998-3874","geo":{"lat":"-37.3159","lng":"81.1496"}},"phone":"1-770-736-8031 x56442","website":"hildegard.org","company":{"name":"Romaguera-Crona","catchPhrase":"Multi-layered client-server neural-net","bs":"harness real-time e-markets"}}
但是为什么,当使用 JSON.stringify 时有一个值,但是没有 JSON.stringify 就没有值(未定义)?
因为请求还没有return结果,用户还在[], 因此,要解决问题,您应该执行以下操作:
return loading? null : (
<div className="card">
<div className="card-header">
{users[0].name}
</div>
</div>
)
这是因为 useEffect 挂钩中的请求是异步的,并且 return 在第一次渲染时没有任何值。所以 users 有初始值 [] .
在显示 users 值之前,您可以使用可选链接或检查加载状态。
return (
<div className="card">
<div className="card-header">
{users[0]?.name}
</div>
</div>
)
或:
return loading ? null : (
<div className="card">
<div className="card-header">
{users[0]?.name}
</div>
</div>
)
还可以更好地处理 name 属性 是空字符串的情况,使用 || 运算符:
return loading ? null : (
<div className="card">
<div className="card-header">
{users[0]?.name || "Anonymous"}
</div>
</div>
)
在 apiRequest
到 return 所需的 3 秒内,您的 Javascript 代码正在尝试尽快编译。
如果您不考虑 readUsers
为 undefined
的 3 秒,您将收到错误消息。
这是因为 readUsers
被初始化为特殊值 undefined
,它没有可访问的方法或值。
如果您打开控制台并尝试输入 undefined[0]
或 undefined.toString()
,您将收到错误消息,因为 undefined
.
为避免错误,您应该提供回退,因此当一个值是 undefined
时执行此操作,然后一旦它变成一个不同的值,该值具有可从中访问的方法和值,就允许它们执行。
import React, { useEffect, useState } from "react";
const oneSecond = 1000;
const threeSeconds = 3 * oneSecond;
// -> Fake API request
function apiRequest() {
// -> Create a new Promise
return new Promise((resolve) =>
// -> Resolve the Promise after waiting three seconds
setTimeout(() => resolve([{ name: "Bill" }]), threeSeconds)
);
}
export default function App() {
const [readUsers, writeUsers] = useState();
useEffect(() => {
// -> Make request (which takes 3 seconds), then update state
apiRequest().then((users) => writeUsers(users));
});
return (
<div>
{readUsers ? (
readUsers.map((user) => <div>{user.name}</div>)
) : (
<div>Loading...</div>
)}
</div>
);
}