英文:
What does it mean "Cannot destructure property 'name' of 'existingUser[0]' as it is undefined. Update.js:13"?
问题
我想要更新用户数据。我可以成功获取现有的用户数据,但无法更新。上面显示了错误。
当我从下面的代码中删除一个等号时,错误消失了,但用户数据仍未更新。
const existingUser = users.userList.filter(f => f.id == id);
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';
import { updateUser } from '../redux/slice/userReducer';
const Update = () => {
const { id } = useParams();
const users = useSelector((state) => state.users);
const existingUser = users.userList.filter(f => f.id === id);
const { name, email } = existingUser[0];
const [uname, setName] = useState(name);
const [uemail, setEmail] = useState(email);
const dispatch = useDispatch();
const navigate = useNavigate();
const handleUpdate = (event) => {
event.preventDefault();
dispatch(updateUser({
id: id,
name: name,
email: email
}));
navigate('/');
}
return (
<div className='d-flex w-100 vh-100 justify-content-center align-items-center'>
<div className='w-50 border bg-secondary text-white p-5'>
<h3>Update User</h3>
<form onSubmit={handleUpdate}>
<div>
<label htmlFor='name'>Name:</label>
<input
type='text'
name='name'
className='form-control'
placeholder='enter name'
value={uname}
onChange={e => setName(e.target.value)}
/>
</div>
<div>
<label htmlFor='name'>Email:</label>
<input
type='email'
name='email'
className='form-control'
placeholder='enter email'
value={uemail}
onChange={e => setEmail(e.target.value)}
/>
</div>
<br />
<button className='btn btn-info'>Update</button>
</form>
</div>
</div>
)
}
export default Update;
英文:
I want to update the user data. I'm getting existing user data successfully but it's not updating. Above error is showing.
When i remove one equal sign from the below line then error removed but still user data not updating.
const existingUser = users.userList.filter(f => f.id == id);
import React, { useState } from 'react'
import { useSelector, useDispatch } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';
import { updateUser } from '../redux/slice/userReducer';
const Update = () => {
const { id } = useParams();
//console.log(id)
const users = useSelector((state) => state.users);
const existingUser = users.userList.filter(f => f.id === id);
//console.log(existingUser);
const { name, email } = existingUser[0];
const [uname, setName] = useState(name);
const [uemail, setEmail] = useState(email);
const dispatch = useDispatch();
const navigate = useNavigate();
const handleUpdate = (event) => {
event.preventDefault();
dispatch(updateUser({
id: id,
name: name,
email: email
}));
navigate('/');
}
return (
<div className='d-flex w-100 vh-100 justify-content-center align-items-center'>
<div className='w-50 border bg-secondary text-white p-5'>
<h3>Update User</h3>
<form onSubmit={handleUpdate}>
<div>
<label htmlFor='name'>Name:</label>
<input
type='text'
name='name'
className='form-control'
placeholder='enter name'
value={uname}
onChange={e => setName(e.target.value)}
/>
</div>
<div>
<label htmlFor='name'>Email:</label>
<input
type='email'
name='email'
className='form-control'
placeholder='enter email'
value={uemail}
onChange={e => setEmail(e.target.value)}
/>
</div>
<br />
<button className='btn btn-info'>Update</button>
</form>
</div>
</div>
)
}
export default Update
答案1
得分: 1
我不确定你的数据结构是什么,但从提供的代码中,我可以解释和猜测问题所在。
你收到的错误意味着你的 existingUser
的第 0 个元素不存在。由于 existingUser
是来自于一个筛选器(filter),而筛选器返回一个数组,我们可以假设筛选器内部的条件没有满足任何元素。
当你说将 ===
改为 ==
后问题解决了,我们可以猜测 f.id 和 id 的类型不同。也许一个是字符串,另一个是整数。
使用 == 实际上解决了你的初始问题。但如果你想使用 ===,你可以尝试更改值的类型。例如,如果 id 是一个字符串,而 f.id 是一个整数,你可以这样写条件:
f.id === parseInt(id)
你可以通过搜索 Google 来了解它们之间的区别。
你接下来的问题是,在修复上述错误后,数据没有更新。这是因为你在组件中使用的设计模式。useState 只接受一个初始值,在组件生命周期内不会更改,除非你使用 setState
进行更新。
由于你正在使用 useSelector 和 dispatch,我假设你正在使用 redux
。在这种情况下,我认为不需要使用 useState
。你可以简单地使用从 existingUser[0]
解构出的 name
和 email
,它们将在你进行 dispatch
更新时呈现。
英文:
I'm not sure what your data structure is, but from the provided codes I can explain and guess what the problem is.
The error you get means that the 0th element of your existingUser
doesn't exist. Since existingUser
is coming from a filter and filter returns an array, we can assume that the condition inside the filter isn't meet for any of the elements.
When you said that changing ===
to ==
causes it to be working, we can guess that f.id and id aren't of the same type. Maybe one is a string and the other is an integer.
Using == has actually solved your initial problem. But if you want to use === you can try changing the values' types. For example if id is a string and f.id is an integer, you can write the condition like this:
f.id === parseInt(id)
You can learn about their differences by searching Google.
Your next issue is that after the above error is fixed the data isn't updated. This is because of the design pattern you have used in your component. A useState only takes one initial value and doesn't change throughout component lifecycle unless you update it using setState
.
Since you're using useSelector and dispatch, I assume you're using redux
. In this case I don't see the need for a useState
. You can simply use the name
and email
you destructure from your existingUser[0]
and they will render whenever you dispatch updates
.
答案2
得分: 0
问题
路由路径参数始终是字符串类型,因此如果任何f.id === id
比较失败,但f.id == id
有效,则表示操作数之间存在类型不匹配。在使用严格相等性*===
时,要比较的值必须具有相同的类型。宽松相等性==
*检查会在比较之前尝试进行类型转换。
考虑以下内容:
console.log('"5" === 5', "5" === 5); // false
console.log('"5" == 5', "5" == 5); // true
有关更多详细信息,请参见Equality comparisons and sameness。
Array.prototype.filter
也可能在源数组中没有元素通过过滤谓词时返回一个空数组,因此代码不应假设有元素来解构属性。
解决方案
代码应该应用一种类型安全的比较。我建议使用字符串比较,以便可以比较字符串和类似数字的字符串。尝试将非数值字符串转换为数字并不总是有效。
console.log('"5" === String(5)', "5" === String(5)); // true
console.log('"5" == String(5)', "5" == String(5)); // true
console.log(
'"12ab34cd56ef78-90" === Number("12ab34cd56ef78-90")',
"12ab34cd56ef" === Number("12ab34cd56ef78-90")
); // false, 12ab34cd56ef78-90 <=> NaN
我建议改用Array.prototype.find
,并提供一个已定义的回退对象值以从中解构值。
const { id } = useParams(); // 字符串类型
const users = useSelector((state) => state.users);
const existingUser = users.userList.find(f => String(f.id) === id); // 类型安全比较
const { name, email } = existingUser ?? {}; // 用于解构的回退值
const [uname, setName] = useState(name ?? ""); // 回退值
const [uemail, setEmail] = useState(email ?? ""); // 回退值
您还可以在选择器函数中执行大部分操作。
const { id } = useParams(); // 字符串类型
const { name, email } = useSelector((state) => {
return state.users.userList.find(f => String(f.id) === id) ?? {};
});
const [uname, setName] = useState(name ?? "");
const [uemail, setEmail] = useState(email ?? "");
另外,您应该使用已更新的本地状态值分派updateUser
操作。
const handleUpdate = (event) => {
event.preventDefault();
dispatch(updateUser({
id,
name: uname,
email: uemail
}));
navigate('/');
};
英文:
Issue
Route path params are always a string type, so if any f.id === id
comparison fails but f.id == id
works then this indicates a type mismatch between operands. When using strict equality ===
then the values being compared need to be of the same type. Loose equality ==
checks will do attempt a type conversion prior to comparison.
Consider the following:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
console.log('"5" === 5', "5" === 5); // false
console.log('"5" == 5', "5" == 5); // true
<!-- end snippet -->
See Equality comparisons and sameness for more details.
The Array.prototype.filter
also potentially returns an empty array if no elements in the source array pass the filtering predicate, so the code should not assume a populated array with elements to destructure properties from.
Solution
The code should apply a type-safe comparison. I suggest using string comparison so both strings and number-like strings can be compared. Trying to convert non-numeric strings to numbers doesn't always work.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
console.log('"5" === String(5)', "5" === String(5)); // true
console.log('"5" == String(5)', "5" == String(5)); // true
<!-- end snippet -->
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
console.log(
'"12ab34cd56ef78-90" === Number("12ab34cd56ef78-90")',
"12ab34cd56ef" === Number("12ab34cd56ef78-90")
); // false, 12ab34cd56ef78-90 <=> NaN
<!-- end snippet -->
I would suggest using Array.prototype.find
instead, and provide a defined fallback object value to destructure values from.
const { id } = useParams(); // String type
const users = useSelector((state) => state.users);
const existingUser = users.userList.find(f => String(f.id) === id); // Type-safe compare
const { name, email } = existingUser ?? {}; // Fallback value to destructure from
const [uname, setName] = useState(name ?? ""); // fallback value
const [uemail, setEmail] = useState(email ?? ""); // fallback value
You could also do much of this in the selector function.
const { id } = useParams(); // String type
const { name, email } = useSelector((state) => {
return state.users.userList.find(f => String(f.id) === id) ?? {};
});
const [uname, setName] = useState(name ?? "");
const [uemail, setEmail] = useState(email ?? "");
Additionally, you should dispatch the updateUser
action with the local state values that were updated.
const handleUpdate = (event) => {
event.preventDefault();
dispatch(updateUser({
id,
name: uname,
email: uemail
}));
navigate('/');
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论