Создайте приложение CRUD с помощью React Hooks и Context API

Я хочу создать приложение 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;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
40
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблемы

  1. Array.prototype.find возвращает либо первое совпадение в массиве, либо undefined, если совпадений нет. Если в массиве не найдено совпадений, вы, вероятно, не хотите обновлять состояние selectedUser до неопределенного.
  2. Если/когда состояние 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;
  }
};

спасибо за помощь. но есть еще одна проблема: когда я нажимаю кнопку редактирования после редактирования пользователя, он переходит на домашнюю страницу, но редактирование не отображается на домашней странице, и пользователь остается без изменений!

Negin 15.05.2022 14:28

@Негин, я вижу. Ничто явно не выделяется как проблема в коде, которым вы поделились для диспетчеризации действий пользователя редактирования и маршрутизации/навигации. Думаете, вы могли бы создать демонстрацию Бег codeandbox вашего кода, которая воспроизводит эту проблему, которую мы могли бы проверить и отладить вживую?

Drew Reese 15.05.2022 21:26
кодыпесочница. благодарю вас.
Negin 16.05.2022 06:51

@Negin Параметр маршрута редактирования — id, а не currentUserId, currentUserId не определен в компоненте, поэтому он не может найти совпадение. В компоненте EditUser используйте const { id } = useParams(); и переименуйте все варианты использования currentUserId в id. codeandbox.io/s/…

Drew Reese 16.05.2022 07:16

Другие вопросы по теме