Данные не передаются в качестве реквизита в React

Итак, для некоторого контекста я создаю небольшой веб-сайт, используя стек мернов (React, инструментарий Redux, Mongo, Express) для моего отца и его дилерского центра. Я столкнулся с проблемой на переднем конце в отношении моей формы редактирования пользователя. в настоящее время я не настроил токены jwt или какие-либо защищенные маршруты, которые появятся в будущем. однако я создал возможность создания формы сведений об учетной записи пользователя, которая отправляется в серверную часть и обрабатывается. Это связано с моей проблемой, которая представляет собой форму редактирования пользователя.

Когда на /users в URL-адресе моего интерфейса вам предоставляется страница со списком всех пользователей и их конкретными данными. У меня также есть кнопка редактирования, которая после нажатия должна перевести вас на страницу редактирования пользовательской формы, чтобы вы могли редактировать данные этого пользователя. Вот и я столкнулся со своей проблемой. Когда я нажимаю «Изменить» для кого-то с ролью дилера (есть три роли: дилер, администратор и клиент), вы можете редактировать их данные без проблем, это работает, логика правильная и все происходит так, как ожидалось. когда вы пытаетесь сделать то же самое с кем-либо с ролью администратора или клиента, это не работает, выдает ошибку, которую вы увидите на изображениях ниже. Я предполагаю, что эта ошибка связана с тем, что данные не передаются правильно, поэтому чтение не определено. некоторые из приведенных ниже изображений размыты, чтобы скрыть конфиденциальную информацию пользователей.

страница со списком пользователей когда вы нажимаете «Изменить» для кого-то с ролью дилера, все работает нормально, как показано на изображении ниже. Пользователь с ролью дилера в форме редактирования пользователя Теперь, когда вы нажимаете «Изменить» для кого-то с любой другой ролью, вы получаете следующую ошибку. Ошибка на недилерских ролях

Вот код для EditUser.js

import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { selectUserById } from "./usersApiSlice";
import EditUserForm from "./EditUserForm";

const EditUser = () => {
  const { id } = useParams();

  const user = useSelector((state) => selectUserById(state, id));

  const content = user ? <EditUserForm user = {user} /> : <p>Loading...</p>;

  return content;
};

export default EditUser;

Вот код для EditUserForm.js

import { useState, useEffect } from "react";
import { useUpdateUserMutation, useDeleteUserMutation } from "./usersApiSlice";
import { useNavigate } from "react-router-dom";
import { ROLES } from "../../config/roles";

const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const PWD_REGEX = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W).{8,}$/;

const EditUserForm = ({ user }) => {
  const [updateUser, { isLoading, isSuccess, isError, error }] =
    useUpdateUserMutation();

  const [
    deleteUser,
    { isSuccess: isDelSuccess, isError: isDelError, error: delerror },
  ] = useDeleteUserMutation();

  const navigate = useNavigate();

  const [email, setEmail] = useState(user.email);
  const [validEmail, setValidEmail] = useState(false);
  const [password, setPassword] = useState("");
  const [validPassword, setValidPassword] = useState(false);
  const [firstname, setFirstname] = useState(user.firstname);
  const [lastname, setLastname] = useState(user.lastname);
  const [telephone, setTelephone] = useState(user.telephone);
  const [roles, setRoles] = useState(user.roles);
  const [profilePicture, setProfilePicture] = useState(user.profilePicture);
  const [companyName, setCompanyName] = useState(user.companyName);

  useEffect(() => {
    if (isSuccess || isDelSuccess) {
      setEmail("");
      setPassword("");
      setRoles([]);
      setFirstname("");
      setLastname("");
      setTelephone("");
      setProfilePicture("");
      setCompanyName("");
      navigate("/dashboard/settings");
    }
  }, [isSuccess, isDelSuccess, navigate]);

  useEffect(() => {
    setValidEmail(EMAIL_REGEX.test(email));
  }, [email]);

  useEffect(() => {
    setValidPassword(PWD_REGEX.test(password));
  }, [password]);

  const onEmailChanged = (e) => setEmail(e.target.value);
  const onPasswordChanged = (e) => setPassword(e.target.value);

  const onRolesChanged = (e) => {
    const values = Array.from(
      e.target.selectedOptions, //HTMLCollection
      (option) => option.value
    );
    setRoles(values);
  };

  const onFirstnameChanged = (e) => setFirstname(e.target.value);
  const onLastnameChanged = (e) => setLastname(e.target.value);
  const onTelephoneChanged = (e) => setTelephone(e.target.value);
  const onProfilePictureChanged = (e) => setProfilePicture(e.target.value);
  const onCompanyNameChanged = (e) => setCompanyName(e.target.value);
    }));
  };

  const onSaveUserClicked = async (e) => {
    if (password) {
      await updateUser({
        id: user.id,
        email,
        password,
        roles,
        firstname,
        lastname,
        telephone,
        profilePicture,
      });
    } else {
      await updateUser({
        id: user.id,
        email,
        roles,
        firstname,
        lastname,
        telephone,
        profilePicture,
        companyName,
      });
    }
  };

  const onDeleteUserClicked = async () => {
    await deleteUser({ id: user.id });
  };

  const options = Object.values(ROLES).map((role) => {
    return (
      <option key = {role} value = {role}>
        {" "}
        {role}
      </option>
    );
  });

  let canSave;

  if (password) {
    canSave =
      roles.length > 0 &&
      password &&
      validEmail &&
      validPassword &&
      firstname.trim().length > 0 &&
      lastname.trim().length > 0 &&
      (telephone.trim().length === 0 || /^[0-9]+$/.test(telephone)) &&
      !isLoading;
  } else {
    canSave =
      roles.length > 0 &&
      validEmail &&
      firstname.trim().length > 0 &&
      lastname.trim().length > 0 &&
      (telephone.trim().length === 0 || /^[0-9]+$/.test(telephone)) &&
      !isLoading;
  }

  const errClass = isError || isDelError ? "errmsg" : "offscreen";
  const validEmailClass = validEmail ? "" : "form__input--incomplete";
  const validPwdClass = validPassword ? "" : "form__input--incomplete";
  const validRolesClass = roles.length > 0 ? "" : "form__input--incomplete";
  const validFirstNameClass =
    firstname.trim().length > 0 ? "" : "form__input--incomplete";
  const validLastNameClass =
    lastname.trim().length > 0 ? "" : "form__input--incomplete";
  const validTelephoneClass =
    telephone.trim().length === 0 || /^[0-9]+$/.test(telephone)
      ? ""
      : "form__input--incomplete";
  const validCompanyNameClass =
    !Object.values(ROLES).includes("Dealership") ||
    companyName.trim().length > 0
      ? ""
      : "form__input--incomplete";
  const validProfilePictureClass =
    profilePicture.trim().length > 0 ? "" : "form__input--incomplete";

  const errContent = (error?.data?.message || delerror?.data?.message) ?? "";

  const content = (
    <>
      <p className = {errClass}>{errContent}</p>

      <form className = "editUserForm" onSubmit = {onSaveUserClicked}>
        <h2 className = "signUp">EditUserForm</h2>

        <div className = "inputFields">
          <label className = "form__label--visually-hidden" htmlFor = "email">
            Email: <span className = "nowrap">[Must include @]</span>
          </label>
          <input
            className = {`form__input ${validEmailClass}`}
            id = "email"
            name = "email"
            type = "text"
            autoComplete = "off"
            value = {email}
            onChange = {onEmailChanged}
            onFocus = {(e) => {
              if (e.target.value === "Email") {
                e.target.value = "";
              }
            }}
            onBlur = {(e) => {
              if (e.target.value === "") {
                e.target.value = "Email";
              }
            }}
            placeholder = "Email"
          />

         <label className = "form__label--visually-hidden" htmlFor = "roles">
            ASSIGNED ROLES:
          </label>
          <select
            id = "roles"
            name = "roles"
            className = {`form__select ${validRolesClass}`}
            multiple = {true}
            size = "3"
            value = {roles}
            onChange = {onRolesChanged}
          >
            {options}
          </select>

        
        <div className = "form__action-buttons">
          <button
            className = "icon-button"
            title = "Save"
            disabled = {!canSave}
            onClick = {onSaveUserClicked}
          >
            Save
          </button>
          <button
            className = "icon-button"
            title = "delete"
            onClick = {onDeleteUserClicked}
          >
            delete
          </button>
        </div>
      </form>
    </>
  );

  return content;
};

export default EditUserForm;

Я удалил часть формы, так как она занимает много места, большинство полей похожи на поле электронной почты выше. Вот и мой файл roles.js.

export const ROLES = {
  Customer: "Customer",
  Dealership: "Dealership",
  Admin: "Admin",
};

Если есть какие-либо другие файлы, которые вы хотели бы увидеть, сообщите мне, например, usersApiSlice.js, store.js и т. д., если вы хотите увидеть дерево файлов, пожалуйста, дайте мне знать. Я хотел бы упомянуть, что я протестировал свой бэкэнд с почтальоном со всеми грубыми операциями. У меня также нет ошибок в моих регистраторах ошибок промежуточного программного обеспечения. Кажется, что проблема не в бэкэнде, а в переднем конце. Я ценю, если кто-то нашел время, чтобы прочитать это.

вот мой store.js

import { configureStore } from "@reduxjs/toolkit";
import { apiSlice } from "./api/apiSlice";
import { setupListeners } from "@reduxjs/toolkit/dist/query";

export const store = configureStore({
  reducer: {
    [apiSlice.reducerPath]: apiSlice.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(apiSlice.middleware),
  devTools: true,
});

setupListeners(store.dispatch);

Вот мои пользователиApiSlice.js

import { createSelector, createEntityAdapter } from     "@reduxjs/toolkit";
import { apiSlice } from "../../app/api/apiSlice";

const usersAdapter = createEntityAdapter({});

const initialState = usersAdapter.getInitialState();

export const usersApiSlice = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    getUsers: builder.query({
      query: () => "/users",
      validateStatus: (response, result) => {
        return response.status === 200 && !result.isError;
      },
      transformResponse: (responseData) => {
        const loadedUsers = responseData.map((user) => {
          user.id = user._id;
          return user;
        });
        return usersAdapter.setAll(initialState, loadedUsers);
      },
      providesTags: (result, error, arg) => {
        if (result?.ids) {
          return [
            { type: "User", id: "LIST" },
            ...result.ids.map((id) => ({ type: "User", id })),
          ];
        } else return [{ type: "User", id: "LIST" }];
      },
    }),
    addNewUser: builder.mutation({
      query: (initialUserData) => ({
        url: "/users",
        method: "POST",
        body: {
          ...initialUserData,
        },
      }),
      invalidatesTags: [{ type: "User", id: "LIST" }],
    }),
    updateUser: builder.mutation({
      query: (initialUserData) => ({
        url: "/users",
        method: "PATCH",
        body: {
          ...initialUserData,
        },
      }),
      invalidatesTags: (result, error, arg) => [{ type: "User", id: arg.id }],
    }),
    deleteUser: builder.mutation({
      query: ({ id }) => ({
        url: `/users`,
        method: "DELETE",
        body: { id },
      }),
      invalidatesTags: (result, error, arg) => [{ type: "User", id: arg.id }],
    }),
  }),
});

export const {
  useGetUsersQuery,
  useAddNewUserMutation,
  useUpdateUserMutation,
  useDeleteUserMutation,
} = usersApiSlice;

// returns the query result object
export const selectUsersResult =   usersApiSlice.endpoints.getUsers.select();

// creates memoized selector
const selectUsersData = createSelector(
  selectUsersResult,
  (usersResult) => usersResult.data 
// normalized state object with ids & entities
);

//getSelectors creates these selectors and we rename them
 with aliases using destructuring
export const {
  selectAll: selectAllUsers,
  selectById: selectUserById,
  selectIds: selectUserIds,
  // Pass in a selector that returns the users slice of state
} = usersAdapter.getSelectors(
  (state) => selectUsersData(state) ?? initialState
);

Я пробовал такие вещи, как тестирование моего бэкенда, гугление ошибок и моей проблемы и тому подобное. Я даже пытался использовать ИИ, чтобы помочь, но любые предложенные решения не сработали.

можете ли вы объяснить const validCompanyNameClass = !Object.values(ROLES).includes("Dealership") || companyName.trim().length > 0 ? "" : "form__input--incomplete"; этот код вкратце. Ошибка может быть связана с некоторым свойством, к которому вы пытаетесь получить доступ для определенной роли, и оно не определено. Например, администратор и клиент могут не иметь связанного с ними названия компании.

Milan Patel 13.05.2023 21:19

Похоже selectUserById возвращается undefined

Konrad 13.05.2023 21:25

Таким образом, допустимый класс названия компании просто проверяет, являетесь ли вы дилером, вы должны ввести название компании в форму, иначе форма будет неполной, а form__inpute — неполное имя класса будет добавлено в форму, для которой у меня есть CSS для

sami 13.05.2023 21:32

Странно то, что эта ошибка возникает только у пользователей со статусом администратора или клиента, @Konrad. С дилерами работает нормально. Я думаю, что вы правы, хотя, как бы я проверил, если это так.

sami 13.05.2023 21:35

Рассмотрите возможность добавления кода этой функции здесь и, возможно, кода хранилища избыточности.

Konrad 14.05.2023 00:21

@Konrad да, отредактировал пост, он внизу

sami 14.05.2023 14:19

Вы проверили вкладку сети в инструментах разработчика, чтобы увидеть, одинаковы ли ответы для разных ролей? К сожалению, я не вижу здесь ничего, что могло бы вызвать эту ошибку.

Konrad 14.05.2023 20:52

Я попробую это, и я буду держать вас в курсе, спасибо за вашу помощь, братан, очень ценю это.

sami 15.05.2023 11:52

я получаю статус 200 для пользователей. никаких 404 и других ошибок. Я ценю вашу помощь, человек, это одна странная проблема. плохо разберусь в конце концов 😅

sami 15.05.2023 16:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
9
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я получал undefined, потому что форма была универсальной для всех пользователей, когда у пользователей с разными ролями были дополнительные биты полей данных. это означало, что форма читалась неопределенной в некоторых частях, таких как companyName, потому что у клиента ее нет. это объясняет, почему форма работала только с ролью дилера, а не с какой-либо другой ролью, потому что данные, которых там не было, пытались получить доступ, поэтому читались как неопределенные. Подумайте о том, чтобы иметь отдельные формы для разных ролей и условно передавать пользователя этим формам.

  const content = user ? (
user.role === "dealership" ? (
  <EditDealerForm user = {user} />
) : (
  <EditUserForm user = {user} />
)

) : (

Загрузка...

);

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