Я хочу создать приложение CRUD с помощью React Hooks и Context API. моя проблема в компоненте EditUser. когда я нажимаю кнопку редактирования, чтобы изменить пользователя, он ничего не показывает на странице, и в консоли у меня есть эта ошибка:
selectedUser не определено для этой части value = {selectedUser.name} name = "name"
<Input type='text' palaceholder = "Enter Name"
value = {selectedUser.name} name = "name"
onChange = {(e) => handleOnChange("name", e.target.value)}
></Input>
спасибо за помощь!
Вот мои компоненты:
GlobalState компонент:
import React, { createContext, useReducer } from 'react'
import AppReducer from './AppReducer'
//Initial State
const initialState = {
users: [
]
}
//Create Context
export const GlobalContext = createContext(initialState);
//Provider Component
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(AppReducer, initialState);
//Actions
const removeUser = (id) => {
dispatch({
type: 'REMOVE_USER',
payload: id
})
}
const addUser = (user) => {
dispatch({
type: 'ADD_USER',
payload: user
})
}
const editUser = (user) => {
dispatch({
type: 'EDIT_USER',
payload: user
})
}
return (
<GlobalContext.Provider value = {{ users: state.users, removeUser, addUser, editUser }}>
{children}
</GlobalContext.Provider>
)
}
AppReducer компонент:
export default (state, action) => {
switch (action.type) {
case 'REMOVE_USER':
return {
users: state.users.filter(user => {
return user.id !== action.payload
})
}
case 'ADD_USER':
return {
users: [action.payload, ...state.users]
}
case 'EDIT_USER':
const updateUser = action.payload;
const editUsers = state.users.map(user => {
if (user.id === updateUser.id) {
return updateUser
}
return user
});
return {
users: editUsers
}
default:
return state
}
}
и наконецEditUserкомпонент:
import { Link, useNavigate, useParams } from 'react-router-dom';
import { GlobalContext } from '../context/GlobalState';
import React,{ useContext, useState, useEffect } from 'react';
import {
Form,
FormGroup,
Label,
Input,
Button
} from 'reactstrap'
const EditUser = () => {
const [selectedUser, setSelectedUser] = useState({
id: "",
name:""
})
const { users, editUser } = useContext(GlobalContext)
const navigate = useNavigate()
const { currentUserId } = useParams();
useEffect(() => {
const userId = currentUserId;
const selectedUser = users.find(user => user.id === parseInt(userId));
setSelectedUser(selectedUser);
}, [currentUserId, users])
const handleSubmit = (e) => {
e.preventDefault();
editUser(selectedUser);
navigate('/');
};
const handleOnChange = (userKey, newValue) => {
setSelectedUser({ ...selectedUser, [userKey]: newValue })
};
return (
<Form onSubmit = {handleSubmit}>
<FormGroup>
<Label>Name</Label>
<Input type='text' palaceholder = "Enter Name"
value = {selectedUser.name} name = "name"
onChange = {(e) => handleOnChange("name", e.target.value)}
></Input>
</FormGroup>
<Button type='submit' className='bg-success '>Edit Name</Button>
<Link to = "/" className = "btn btn-danger m-2">Cancel</Link>
</Form>
);
}
export default EditUser;





Array.prototype.find возвращает либо первое совпадение в массиве, либо undefined, если совпадений нет. Если в массиве не найдено совпадений, вы, вероятно, не хотите обновлять состояние selectedUser до неопределенного.selectedUser не определено, попытка доступа к свойствам неопределенного приведет к ошибке, которую вы видите. Используйте null-check/guard-clause или необязательный оператор цепочки, чтобы предотвратить случайный доступ к потенциально нулевым или неопределенным объектам.Ставьте обновления selectedUser в очередь только в том случае, если есть соответствующий пользователь для обновления.
const { currentUserId } = useParams();
useEffect(() => {
const userId = currentUserId;
const selectedUser = users.find(user => String(user.id) === userId);
if (selectedUser) {
setSelectedUser(selectedUser);
}
}, [currentUserId, users]);
Защитите доступ к вложенным свойствам currentUser и укажите допустимое определенное резервное значение для input, чтобы он не вызывал ошибок при переключении между контролируемым и неконтролируемым. Рефакторинг handleOnChange, чтобы использовать событие onChange и деструктурировать входное имя и значение из него, а также использовать обновление функционального состояния для обновления предыдущего состояния.
const handleOnChange = (e) => {
const { name, value } = e.target;
setSelectedUser(selectedUser => ({
...selectedUser,
[name]: value
}));
};
...
<FormGroup>
<Label>Name</Label>
<Input
type='text'
palaceholder = "Enter Name"
value = {selectedUser?.name ?? ""}
name = "name"
onChange = {handleOnChange}
/>
</FormGroup>
Это лишь незначительный момент, касающийся логики функции редуктора. То, что у вас есть, в порядке, так как единственное свойство, которое есть у userReducer, — это свойство users, но это соглашение функции редуктора, которое также неглубоко копирует предыдущий state.
Пример:
export default (state, action) => {
switch (action.type) {
case 'REMOVE_USER':
return {
...state,
users: state.users.filter(user => user.id !== action.payload),
}
case 'ADD_USER':
return {
...state,
users: [action.payload, ...state.users],
}
case 'EDIT_USER':
const updateUser = action.payload;
return {
...state,
users: state.users.map(user => user.id === updateUser.id
? updateUser
: user
),
}
default:
return state;
}
};
@Негин, я вижу. Ничто явно не выделяется как проблема в коде, которым вы поделились для диспетчеризации действий пользователя редактирования и маршрутизации/навигации. Думаете, вы могли бы создать демонстрацию Бег codeandbox вашего кода, которая воспроизводит эту проблему, которую мы могли бы проверить и отладить вживую?
@Negin Параметр маршрута редактирования — id, а не currentUserId, currentUserId не определен в компоненте, поэтому он не может найти совпадение. В компоненте EditUser используйте const { id } = useParams(); и переименуйте все варианты использования currentUserId в id. codeandbox.io/s/…
спасибо за помощь. но есть еще одна проблема: когда я нажимаю кнопку редактирования после редактирования пользователя, он переходит на домашнюю страницу, но редактирование не отображается на домашней странице, и пользователь остается без изменений!