javascript - React app throws TypeError: Cannot read properties of undefined (reading 'name') when compiling - S

I keep running into an issue with my CRUD application when I go to edit a name from my list, it throws

I keep running into an issue with my CRUD application when I go to edit a name from my list, it throws an error "TypeError: Cannot read properties of undefined (reading 'name')".

It seems to stem from the "value={selectedUser.name}" in my input field, but when I remove it the app piles but I cannot alter the field at all - nothing happens when you type. Any help is appreciated!

import React, { useState, useContext, useEffect } from 'react'
import { GlobalContext } from '../context/GlobalState'
import { Link, useNavigate, useParams } from 'react-router-dom'
import { Form, FormGroup, Label, Input, Button } from 'reactstrap'

const EditUser = (props) => {
const [selectedUser, setSelectedUser] = useState({
  id: '',
  name: ''
});
const { users, editUser } = useContext(GlobalContext);
const navigate = useNavigate();
const currentUserId = useParams(props);

useEffect(() => {
  const userId = currentUserId;
  const selectedUser = users.find(user => user.id === userId)
  setSelectedUser(selectedUser)
}, [currentUserId, users])

const onSubmit = (e) => {
  e.preventDefault()
  editUser(selectedUser)
  navigate('/');
}

const onChange = (e) => {
  setSelectedUser({...selectedUser, [e.target.name]: e.target.value})
}

  return (
    <div>
        <Form onSubmit={onSubmit}>
            <FormGroup>
                <Label>Edit Name</Label>
                <Input type='text' name='name' value={selectedUser.name} onChange={onChange} placeholder='Enter Name'></Input>
            </FormGroup>
        <Button type='submit'>Edit Name</Button>
        <Link to='/' className='btn btn-danger m-2'>Back</Link>
        </Form>
    </div>
  )
}

export default EditUser

I keep running into an issue with my CRUD application when I go to edit a name from my list, it throws an error "TypeError: Cannot read properties of undefined (reading 'name')".

It seems to stem from the "value={selectedUser.name}" in my input field, but when I remove it the app piles but I cannot alter the field at all - nothing happens when you type. Any help is appreciated!

import React, { useState, useContext, useEffect } from 'react'
import { GlobalContext } from '../context/GlobalState'
import { Link, useNavigate, useParams } from 'react-router-dom'
import { Form, FormGroup, Label, Input, Button } from 'reactstrap'

const EditUser = (props) => {
const [selectedUser, setSelectedUser] = useState({
  id: '',
  name: ''
});
const { users, editUser } = useContext(GlobalContext);
const navigate = useNavigate();
const currentUserId = useParams(props);

useEffect(() => {
  const userId = currentUserId;
  const selectedUser = users.find(user => user.id === userId)
  setSelectedUser(selectedUser)
}, [currentUserId, users])

const onSubmit = (e) => {
  e.preventDefault()
  editUser(selectedUser)
  navigate('/');
}

const onChange = (e) => {
  setSelectedUser({...selectedUser, [e.target.name]: e.target.value})
}

  return (
    <div>
        <Form onSubmit={onSubmit}>
            <FormGroup>
                <Label>Edit Name</Label>
                <Input type='text' name='name' value={selectedUser.name} onChange={onChange} placeholder='Enter Name'></Input>
            </FormGroup>
        <Button type='submit'>Edit Name</Button>
        <Link to='/' className='btn btn-danger m-2'>Back</Link>
        </Form>
    </div>
  )
}

export default EditUser
Share Improve this question edited May 20, 2022 at 3:03 Drew Reese 204k18 gold badges246 silver badges274 bronze badges asked May 20, 2022 at 1:29 David FeudaleDavid Feudale 1671 gold badge1 silver badge14 bronze badges 2
  • 1 value={selectedUser?.name}. Does this fix your problem ? – Bas Commented May 20, 2022 at 1:33
  • No :( Failed to pile ./src/ponents/EditUser.js 78:24 Module parse failed: Unexpected token (78:24) You may need an appropriate loader to handle this file type. | type: "text", | name: "name", > value: selectedUser?.name, | onChange: onChange, | placeholder: "Enter Name", – David Feudale Commented May 20, 2022 at 1:37
Add a ment  | 

2 Answers 2

Reset to default 2

If currentUserId is undefined for any reason, or your users.find() returns undefined, then you're going to be storing undefined in your selectedUser state variable.

Given from your ments it looks like you're not able to use optional chaining (the foo?.bar syntax) then you probably just want to prevent this at source:

  useEffect(() => {
    const userId = currentUserId;
    const foundUser = users.find((user) => user.id === userId);
    if (foundUser) {
      setSelectedUser(foundUser);
    } 
  }, [currentUserId, users]);

Also note I renamed your variable inside your useEffect to avoid confusion with your selectedUser at the higher level.

Issue

Array.prototype.find returns the first matching element, or undefined if no such match is found.

const selectedUser = users.find(user => user.id === userId); // potentially undefined

Additionally, the returned value from the useParams hook is an object of the key-value pairs of any defined route path parameters. The code appears to incorrectly assume the returned value is the currentUserId parameter from a path, and uses that to search the users array.

const currentUserId = useParams(props);

useEffect(() => {
  const userId = currentUserId;
  const selectedUser = users.find(user => user.id === userId);
  setSelectedUser(selectedUser);
}, [currentUserId, users]);

I doubt there could ever be a found match paring user.id against the returned params object.

Solution

I suspect that the actual path param is really userId. Either destructure it immediately from the useParams hook.

const { userId } = useParams();

or rename currentUserId to params and destructure userId in the hook.

const params = useParams(props);

useEffect(() => {
  const { userId } = params;
  const selectedUser = users.find(user => user.id === userId);
  setSelectedUser(selectedUser);
}, [params.userId, users]);

One last point about route params and id properties. The route params will always be a string type. Sometimes the id is actually a number type, so you'll want to use a type-safe equality check. Convert ids to string types, which covers both string ids and will convert numbers to number-like strings.

useEffect(() => {
  const { userId } = params;
  const selectedUser = users.find(user => String(user.id) === userId);
  setSelectedUser(selectedUser);
}, [params.userId, users]);

Guarding against null/undefined values.

  1. First, try to maintain a stable selectedUser state invariant. In other words, don't update it an undefined value unless you have a specific need to. Check the result of users.find to see if a match was found.

    const { userId } = useParams(props);
    
    useEffect(() => {
      const selectedUser = users.find(user => String(user.id) === userId);
      if (selectedUser) {
        setSelectedUser(selectedUser);
      }
    }, [userId, users]);
    
  2. Second, defensively guard against potentially null/undefined accesses in your render function, just in case. You can use the Optional Chaining and Nullish Coalescing Operators to guard null access and provide a valid defined value for the controlled input.

    <Input
      type='text'
      name='name'
      value={selectedUser?.name ?? ""}
      onChange={onChange}
      placeholder='Enter Name'
    />
    

    or if you prefer older-school null-checks/guard-clauses

    <Input
      type='text'
      name='name'
      value={(selectedUser && selectedUser.name) ?? ""}
      onChange={onChange}
      placeholder='Enter Name'
    />
    

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745377140a4625052.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信