What does it mean "Cannot destructure property 'name' of 'existingUser[0]' as it is undefined. Update.js:13"?

huangapple go评论69阅读模式
英文:

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 =&gt; f.id == id);

import React, { useState } from &#39;react&#39;
import { useSelector, useDispatch } from &#39;react-redux&#39;;
import { useNavigate, useParams } from &#39;react-router-dom&#39;;
import { updateUser } from &#39;../redux/slice/userReducer&#39;;

const Update = () =&gt; {
  const { id } = useParams();
  //console.log(id)

  const users = useSelector((state) =&gt; state.users);
  const existingUser = users.userList.filter(f =&gt; 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) =&gt; {
    event.preventDefault();
    dispatch(updateUser({
      id: id,
      name: name,
      email: email
    }));
    navigate(&#39;/&#39;);
  }

  return (
    &lt;div className=&#39;d-flex w-100 vh-100 justify-content-center align-items-center&#39;&gt;
      &lt;div className=&#39;w-50 border bg-secondary text-white p-5&#39;&gt;
        &lt;h3&gt;Update User&lt;/h3&gt;
        &lt;form onSubmit={handleUpdate}&gt;
          &lt;div&gt;
            &lt;label htmlFor=&#39;name&#39;&gt;Name:&lt;/label&gt;
            &lt;input
              type=&#39;text&#39;
              name=&#39;name&#39;
              className=&#39;form-control&#39;
              placeholder=&#39;enter name&#39;
              value={uname}
              onChange={e =&gt; setName(e.target.value)}
            /&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;label htmlFor=&#39;name&#39;&gt;Email:&lt;/label&gt;
            &lt;input
              type=&#39;email&#39;
              name=&#39;email&#39;
              className=&#39;form-control&#39;
              placeholder=&#39;enter email&#39;
              value={uemail}
              onChange={e =&gt; setEmail(e.target.value)}
            /&gt;
          &lt;/div&gt;
          &lt;br /&gt;
          &lt;button className=&#39;btn btn-info&#39;&gt;Update&lt;/button&gt;
        &lt;/form&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  )
}

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] 解构出的 nameemail,它们将在你进行 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(&#39;&quot;5&quot; === 5&#39;, &quot;5&quot; === 5); // false
console.log(&#39;&quot;5&quot; == 5&#39;, &quot;5&quot; == 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(&#39;&quot;5&quot; === String(5)&#39;, &quot;5&quot; === String(5)); // true
console.log(&#39;&quot;5&quot; == String(5)&#39;, &quot;5&quot; == String(5));   // true

<!-- end snippet -->

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

console.log(
&#39;&quot;12ab34cd56ef78-90&quot; === Number(&quot;12ab34cd56ef78-90&quot;)&#39;,
&quot;12ab34cd56ef&quot; === Number(&quot;12ab34cd56ef78-90&quot;)
); // false, 12ab34cd56ef78-90 &lt;=&gt; 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) =&gt; state.users);

const existingUser = users.userList.find(f =&gt; String(f.id) === id); // Type-safe compare

const { name, email } = existingUser ?? {}; // Fallback value to destructure from

const [uname, setName] = useState(name ?? &quot;&quot;);    // fallback value
const [uemail, setEmail] = useState(email ?? &quot;&quot;); // fallback value

You could also do much of this in the selector function.

const { id } = useParams(); // String type

const { name, email } = useSelector((state) =&gt; {
  return state.users.userList.find(f =&gt; String(f.id) === id) ?? {};
});

const [uname, setName] = useState(name ?? &quot;&quot;);
const [uemail, setEmail] = useState(email ?? &quot;&quot;);

Additionally, you should dispatch the updateUser action with the local state values that were updated.

const handleUpdate = (event) =&gt; {
  event.preventDefault();
  dispatch(updateUser({
    id,
    name: uname,
    email: uemail
  }));
  navigate(&#39;/&#39;);
};

huangapple
  • 本文由 发表于 2023年6月2日 03:05:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384973.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定