Вопрос или проблема
Когда я нажимаю кнопку “Редактировать”, отображаются поля редактирования для конкретного пользователя. Однако, если я не вношу никаких изменений в поля и перехожу к следующему пользователю (нажав кнопку “Редактировать” для этого пользователя), состояние кнопки предыдущего пользователя не возвращается с “Отправить” на “Редактировать”. Я пытался сравнивать ID с помощью useEffect
, но это не сработало.
Редактировать
import React, { Fragment, useCallback, useEffect, useState } from "react";
import { setCurrentIdUser, setShowEditUser } from "../../redux/usersSlice";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { useUpdateUserMutation } from "../../api";
import { IUsers } from "../../redux/type";
interface EditIdUserProps {
userId: number;
updateEditUser: any;
users: IUsers[];
}
function Edit({ userId, updateEditUser, users }: EditIdUserProps) {
const dispatch = useAppDispatch();
const [updateUser] = useUpdateUserMutation();
const [isEditing, setIsEditing] = useState<boolean>(false); // добавить состояние кнопки
const [prevUserId, setPrevUserId] = useState<number | null>(null);
useEffect(() => {
if (prevUserId !== userId) {
setIsEditing(false);
setPrevUserId(userId);
}
}, [userId, prevUserId]);
const toggleEdit = useCallback(() => {
setIsEditing((prev) => !prev);
dispatch(setCurrentIdUser(userId)); // Обновляет хранилище Redux с текущим ID пользователя
dispatch(setShowEditUser(!isEditing)); // Переключает видимость полей редактирования пользователей
setPrevUserId(userId); // Обновляет предыдущий ID пользователя
}, [dispatch, userId, isEditing]);
const handleUpdateUser = useCallback(async () => {
dispatch(setCurrentIdUser(userId));
dispatch(setShowEditUser(true));
const isEmptyEditUser = Object.keys(updateEditUser).length === 0;
const existingUserData = users.find((user) => user.id === userId);
setPrevUserId(existingUserData?.id || null);
if (!isEmptyEditUser && existingUserData) {
const formattedUpdateData = {
...existingUserData,
...updateEditUser[userId],
address: {
...existingUserData.address,
...updateEditUser[userId]?.address,
},
};
try {
await updateUser(formattedUpdateData as IUsers);
console.log("Обновленные данные", formattedUpdateData);
setIsEditing(false); // Сбрасывает в состояние 'Редактировать' после отправки
dispatch(setShowEditUser(false)); // Закрывает поля редактирования
} catch (error) {
console.log("Ошибка обновления данных", error);
}
setIsEditing(false);
dispatch(setShowEditUser(false));
} else {
// Если нет изменений для редактирования
console.log("Нет изменений для обновления");
setIsEditing(false);
dispatch(setShowEditUser(false));
}
}, [dispatch, userId, updateEditUser, updateUser, users]);
return (
<Fragment>
<button onClick={isEditing ? handleUpdateUser : toggleEdit}>
{isEditing ? "Отправить" : "Редактировать"}
</button>
</Fragment>
);
}
export default Edit;
СписокПользователей
import React, { useEffect, useState } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { IUsers } from "../../redux/type";
import classes from "./UsersList.module.scss";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
import { setEditUserValues, setShowModalForm } from "../../redux/usersSlice";
import "../../styles/animations.scss";
import DeleteUser from "../UI/DeleteUser";
import Edit from "../UI/Edit";
interface UserProps {
users: IUsers[] | undefined;
deleteUserHandel: (id: number) => void;
}
function UsersList({ users, deleteUserHandel }: UserProps) {
const dispatch = useAppDispatch();
const isEditInput = useAppSelector((state) => state.user.isShowEditUser);
const currentIdEditUser = useAppSelector((state) => state.user.currentIdUser);
const editUserValues = useAppSelector((state) => state.user.editUserValues);
const showUserForm = () => {
dispatch(setShowModalForm(true));
};
// Изменение пользовательского ввода
const handleChange = (
userId: number,
field: keyof IUsers | "address",
value: string,
addressField?: keyof IUsers["address"]
) => {
dispatch(setEditUserValues({ userId, field, value, addressField }));
};
return (
<table className="table">
<thead>
<tr style={{ background: "red" }}>
<th scope="col" style={{ background: "red" }}>
№
</th>
<th scope="col">Имя</th>
<th scope="col">Имя пользователя</th>
<th scope="col">Электронная почта</th>
<th scope="col" style={{ background: "red" }}></th>
<th scope="col" style={{ background: "red" }}>
Адрес
</th>
<th scope="col" style={{ background: "red" }}></th>
<th scope="col">
<button onClick={showUserForm}>Добавить пользователя</button>
</th>
</tr>
</thead>
<tbody>
{users?.map((user) => {
const edit = isEditInput && currentIdEditUser === user.id;
return (
<tr key={user.id} className={classes.background}>
<th scope="row">{user.id}</th>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>{user.name}</p>
{edit && (
<input
onChange={(e) =>
handleChange(user.id, "name", e.target.value)
}
value={editUserValues[user.id]?.name ?? user.name ?? ""}
type="text"
placeholder="имя"
/>
)}
</div>
</td>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>{user.username}</p>
{edit && (
<input
onChange={(e) =>
handleChange(user.id, "username", e.target.value)
}
value={
editUserValues[user.id]?.username ?? user.username ?? ""
}
type="text"
placeholder="имя пользователя"
/>
)}
</div>
</td>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>{user.email}</p>
{edit && (
<input
onChange={(e) =>
handleChange(user.id, "email", e.target.value)
}
value={editUserValues[user.id]?.email ?? user.email ?? ""}
type="email"
placeholder="электронная почта"
/>
)}
</div>
</td>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>Город:</p>
<p>{user.address?.city}</p>
{edit && (
<input
onChange={(e) =>
handleChange(user.id, "address", e.target.value, "city")
}
value={
editUserValues[user.id]?.address?.city ??
user.address?.city ??
""
}
type="text"
placeholder="город"
/>
)}
</div>
</td>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>Улица:</p>
<p>{user.address?.street}</p>
{edit && (
<input
onChange={(e) =>
handleChange(
user.id,
"address",
e.target.value,
"street"
)
}
value={
editUserValues[user.id]?.address?.street ??
user.address?.street ??
""
}
type="text"
placeholder="улица"
/>
)}
</div>
</td>
<td className={classes.content}>
<div className={classes.contentUser}>
<p>Квартира:</p>
<p>{user.address?.suite}</p>
{edit && (
<input
onChange={(e) =>
handleChange(
user.id,
"address",
e.target.value,
"suite"
)
}
value={
editUserValues[user.id]?.address?.suite ??
user.address?.suite ??
""
}
type="text"
placeholder="квартира"
/>
)}
</div>
</td>
<td className={classes.content}>
<Edit
userId={user.id}
updateEditUser={editUserValues}
users={users}
/>
<DeleteUser
id={user.id}
deleteUserHandel={() => deleteUserHandel(user.id)}
/>
</td>
</tr>
);
})}
</tbody>
</table>
);
}
export default UsersList;
Ответ или решение
Проблема с кнопкой "Send" и возвращением к состоянию "Edit" в React-приложении: анализ и решение
При разработке интерфейсов на React иногда возникают ситуации, когда поведение элементов, таких как кнопки, не соответствует ожиданиям. Одной из таких проблем является ситуация, когда кнопка "Send" не меняется обратно на "Edit" после переключения между пользователями в списке. Рассмотрим детали вашей проблемы и предложим возможные решения.
Описание проблемы
В вашем коде мы видим, что при нажатии на кнопку "Edit" отображаются поля редактирования для пользователя. Однако, если пользователь не вносит никаких изменений и переключается на другого пользователя, состояние кнопки предыдущего пользователя остается на значении "Send".
Текущая логика
Вы используете несколько хук-методов, такие как useEffect
, для отслеживания изменения userId
и состояния кнопки с помощью isEditing
. Однако проблема заключается в том, что setIsEditing(false)
должен вызываться в точный момент, когда происходит переключение пользователя, а не лишь по изменению userId
.
Потенциальные решения
1. Обновление состояния в useEffect
Ваш useEffect
не эффективен в контексте обнаружения изменений, если пользователь не вносит изменения в поля. Необходимо добавить логику, которая будет обрабатывать состояние кнопки только при необходимости. Например:
useEffect(() => {
if (prevUserId !== userId) {
setIsEditing(false); // Смена состояния кнопки при переключении пользователя
setPrevUserId(userId);
}
}, [userId, prevUserId]);
Это уже у вас реализовано, но необходимо убедиться, что setIsEditing
вызывается в нужный момент.
2. Обновление состояние на колбэке toggleEdit
Ваша функция toggleEdit
должна также проверять текущее состояние редактирования перед тем, как переключить пользователей. Рассмотрим пример:
const toggleEdit = useCallback(() => {
if (isEditing) {
handleUpdateUser(); // Обработка отправки изменения
} else {
setIsEditing(true); // Включение состояния редактирования
}
dispatch(setCurrentIdUser(userId));
dispatch(setShowEditUser(true));
}, [isEditing, dispatch, userId]);
Этим способом, если пользователь уже редактирует данные, они будут отправлены перед переключением.
3. Дополнительные проверки
Добавьте условные проверки, чтобы гарантировать, что когда происходит переключение на нового пользователя, состояние кнопки предыдущего пользователя возвращается к "Edit".
const handleUpdateUser = useCallback(async () => {
// Логика обновления пользователя...
setIsEditing(false); // Сброс состояния действия после обновления
}, [ /* зависимости */ ]);
Заключение
Необходимо убедиться, что управление состоянием кнопки "Edit"/"Send" четко синхронизировано с изменениями пользователя. Полный контроль над состояниями и использование подходящих хуков React позволит избежать неполадок и снизить вероятность возникновения таких ошибок. Примените предложенные изменения и внимательно следите за состояниями компонентов при переключении между пользователями. Удачи в дальнейшей разработке!