Реакция: ввод текста продолжает терять фокус по мере того, как я печатаю

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

Я также уверен, что «LabelledIconInput» не является проблемой, поскольку я использую его на странице входа в систему, и у меня нет такой проблемы.

Может ли кто-нибудь дать какие-либо указатели, почему это может происходить?

Входные данные, имеющие проблему (они определены в отдельных файлах, находящихся в /components/):

<LabelledDropdown
              label = "SEASON*"
              selectedValue = {seasonName}
              placeholder = "Select a season"
              options = {seasons}
              onSelectOptions = {handleSeasonName}
            ></LabelledDropdown>

<LabelledTextArea
            label = "OUTPUT REQUIREMENT"
            value = {requirements}
            placeholder = {null}
            onChange = {handleRequirements}
          ></LabelledTextArea>

Новая форма заказа:

interface INewOrder {}
const NewOrder: React.FC<INewOrder> = (props) => {
  

  const [orderName, setOrderName] = useState("");
  const [seasonName, setSeasonName] = useState("");
  const [categoryName, setCategoryName] = useState("");
  const [requirements, setRequirements] = useState("");
  const [dateValue, setDateValue] = useState(null);

  const [newUserInfo, setNewUserInfo] = useState({
    profileImages: [],
  });
  const updateUploadedFiles = (files) =>
    setNewUserInfo({ ...newUserInfo, profileImages: files });


  const handleOrderName = (event) => {
    console.info(event);
    setOrderName(event);
  };

  const handleSeasonName = (event) => {
    console.info(event);
    setSeasonName(event);
  };

  const handleCategoryName = (event) => {
    console.info(event);
    setCategoryName(event);
  };

  const handleDateChange = (event) => {
    console.info(event);
    setDateValue(event);
  };

  const handleRequirements = (event) => {
    setRequirements(event);
  };

  return (
    <Container>
      <MyForm onSubmit = {null}>
        <PageTitle>New Order</PageTitle>
        <ProgressIndication>
          <Dots></Dots>
          <Dots></Dots>
          <Dots></Dots>
        </ProgressIndication>
        <br />
        <FormBackground>
          <Subheading>Tell Us a bit more...</Subheading>
          <LabelledIconInput
            label = "ORDER NAME"
            value = {orderName}
            placeholder = "Name"
            onChange = {handleOrderName}
          ></LabelledIconInput>
          <br /> <br />
          <MySpan>
            <LabelledDropdown
              label = "SEASON*"
              selectedValue = {seasonName}
              placeholder = "Select a season"
              options = {seasons}
              onSelectOptions = {handleSeasonName}
            ></LabelledDropdown>
            <LabelledDropdown
              label = "SERVICE CATEGORY"
              selectedValue = {categoryName}
              placeholder = "Select a Category"
              options = {category}
              onSelectOptions = {handleCategoryName}
            ></LabelledDropdown>
          </MySpan>
          <br /> <br />
          <FileUploadComponent
            label = "UPLOAD FILES"
            multiple
          ></FileUploadComponent>
          <LabelledTextArea
            label = "OUTPUT REQUIREMENT"
            value = {requirements}
            placeholder = {null}
            onChange = {handleRequirements}
          ></LabelledTextArea>
          <br />
          <LabelledDateInput
            label = "Expected Delivery Date"
            placeholder = "Select a delivery date"
            dateValue = {dateValue}
            onChange = {handleDateChange}
          ></LabelledDateInput>
          <br />
          <LabelledDropdown
            label = "3D Software"
            width = "100%"
            selectedValue = {software[0].value}
            placeholder = "Select a Category"
            options = {software}
            onSelectOptions = {handleSeasonName}
          ></LabelledDropdown>
        </FormBackground>
        <br />
        <PrimaryButton onClick = {null}>Next</PrimaryButton>
      </MyForm>
    </Container>
  );
};

Стилизованные компоненты (присутствуют в том же файле, что и форма):

const MyForm = styled("form")`
    margin: auto;
  `;

  const Container = styled("div")`
    display: grid;
    justify-content: center;
    grid-template-columns: auto auto;
  `;

  const MySpan = styled("span")``;

  const PageTitle = styled("h2")`
    color: ${colors.theme};
    text-align: center;
    font-weight: 600;
  `;

  const FormBackground = styled("div")`
    background-color: white;
    border-radius: 10px;
    padding: 20px;
  `;

  const Subheading = styled("h3")`
    color: ${colors.theme};
    font-weight: 500;
  `;

  const Dots = styled("li")<IDots>`
    width: 15px;
    height: 15px;
    text-align: center;
    line-height: 2em;
    border-radius: 1em;
    background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
    margin: 0 50px;
    display: inline-block;
    color: white;
    position: relative;

    &&::before {
      content: "";
      position: absolute;
      top: 6px;
      left: -100px;
      width: 7em;
      height: 0.2em;
      background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
      z-index: -1;
    }

    &&:first-child::before {
      display: none;
    }
  `;

  const ProgressIndicator = styled("div")`
    text-align: center;
  `;

Получение следующего предупреждения в браузере при загрузке формы:

[Error] Warning: Expected server HTML to contain a matching <div> in <div>.
    in div (created by Styled(div))
    in Styled(div) (at HyperlinkButton.tsx:21)
    in HyperlinkButton (at Navbar.tsx:111)
    in div (at Navbar.tsx:109)
    in div (created by Styled(div))
    in Styled(div) (at Navbar.tsx:108)
    in div (created by Styled(div))
    in Styled(div) (at Navbar.tsx:99)
    in div (at Navbar.tsx:98)
    in Navbar (at ProtectedPageWrapper.tsx:44)
    in div (created by Styled(div))
    in Styled(div) (at ProtectedPageWrapper.tsx:43)
    in ProtectedPageWrapper (at new-order.tsx:48)
    in Index (created by withI18nextTranslation(Index))
    in withI18nextTranslation(Index) (at _app.tsx:36)
    in MsalProvider (at _app.tsx:35)
    in CookiesProvider (at _app.tsx:34)
    in ErrorBoundary (at _app.tsx:33)
    in MyApp (created by withI18nextSSR(MyApp))
    in withI18nextSSR(MyApp) (created by AppWithTranslation)
    in NextStaticProvider (created by withI18nextTranslation(NextStaticProvider))
    in withI18nextTranslation(NextStaticProvider) (created by AppWithTranslation)
    in I18nextProvider (created by AppWithTranslation)
    in AppWithTranslation (created by withRouter(AppWithTranslation))
    in withRouter(AppWithTranslation) (at withRedux.tsx:12)
    in Provider (at withRedux.tsx:11)
    in withRedux(withRouter(AppWithTranslation))
    in ErrorBoundary (created by ReactDevOverlay)
    in ReactDevOverlay (created by Container)
    in Container (created by AppContainer)
    in AppContainer
    in Root
    (anonymous function) (next-dev.js:60)
    printWarning (react-dom.development.js:88)
    error (react-dom.development.js:60)
    warnForInsertedHydratedElement (react-dom.development.js:6603)
    didNotFindHydratableInstance (react-dom.development.js:7803)
    insertNonHydratedInstance (react-dom.development.js:16504)
    tryToClaimNextHydratableInstance (react-dom.development.js:16575)
    updateHostComponent (react-dom.development.js:17269)
    beginWork$1 (react-dom.development.js:23179)
    performUnitOfWork (react-dom.development.js:22154)
    workLoopSync (react-dom.development.js:22130)
    performSyncWorkOnRoot (react-dom.development.js:21756)
    scheduleUpdateOnFiber (react-dom.development.js:21188)
    updateContainer (react-dom.development.js:24373)
    (anonymous function) (react-dom.development.js:24758)
    unbatchedUpdates (react-dom.development.js:21903)
    legacyRenderSubtreeIntoContainer (react-dom.development.js:24757)
    renderReactElement (index.js:742)
    doRender (index.js:904)
    tryCatch (runtime.js:45)
    invoke (runtime.js:274)
    asyncGeneratorStep (index.js:189)
    _next (index.js:207)
    (anonymous function) (index.js:212)
    Promise
    (anonymous function) (index.js:204)
    _callee$ (index.js:588)
    tryCatch (runtime.js:45)
    invoke (runtime.js:274)
    asyncGeneratorStep (index.js:189)
    _next (index.js:207)
    promiseReactionJob

Полный код:

import styled from "@emotion/styled";
import React, { useState } from "react";
import PrimaryButton from "../buttons/PrimaryButton";
import LabelledDateInput from "../inputs/LabelledDateInput";
import LabelledDropdown from "../inputs/LabelledDropdown";
import LabelledIconInput from "../inputs/LabelledIconInput";
import { colors } from "../../utilities/colors";
import LabelledTextArea from "../inputs/LabelledTextArea";
import FileUploadComponent from "../inputs/FileUploadComponent";

interface INewOrder {}

interface IDots {
  isActive?: boolean;
}

const NewOrder: React.FC<INewOrder> = (props) => {
  const MyForm = styled("form")`
    margin: auto;
  `;

  const Container = styled("div")`
    display: grid;
    justify-content: center;
    grid-template-columns: auto auto;
  `;

  const MySpan = styled("span")``;

  const PageTitle = styled("h2")`
    color: ${colors.theme};
    text-align: center;
    font-weight: 600;
  `;

  const FormBackground = styled("div")`
    background-color: white;
    border-radius: 10px;
    padding: 20px;
  `;

  const Subheading = styled("h3")`
    color: ${colors.theme};
    font-weight: 500;
  `;

  const Dots = styled("li")<IDots>`
    width: 15px;
    height: 15px;
    text-align: center;
    line-height: 2em;
    border-radius: 1em;
    background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
    margin: 0 50px;
    display: inline-block;
    color: white;
    position: relative;

    &&::before {
      content: "";
      position: absolute;
      top: 6px;
      left: -100px;
      width: 7em;
      height: 0.2em;
      background: ${(props) => (props.isActive ? colors.theme : "#e1e5f7")};
      z-index: -1;
    }

    &&:first-child::before {
      display: none;
    }
  `;

  const ProgressIndicator = styled("div")`
    text-align: center;
  `;

  const [orderName, setOrderName] = useState("");
  const [seasonName, setSeasonName] = useState("");
  const [categoryName, setCategoryName] = useState("");
  const [requirements, setRequirements] = useState("");
  const [dateValue, setDateValue] = useState(null);
  const [newUserInfo, setNewUserInfo] = useState({
    profileImages: [],
  });
  const updateUploadedFiles = (files) =>
    setNewUserInfo({ ...newUserInfo, profileImages: files });

  const seasons = [
    {
      value: "New Season",
      label: "New Season",
    },
    {
      value: "Summer 2022",
      label: "Summer 2022",
    },
    {
      value: "Winter 2022",
      label: "Winter 2022",
    },
  ];

  const category = [
    {
      value: "Style",
      label: "Style",
    },
    {
      value: "Trim",
      label: "Trim",
    },
    {
      value: "Fabric",
      label: "Fabric",
    },
    {
      value: "Block",
      label: "Block",
    },
  ];

  const software = [
    {
      value: "3D Max",
      label: "3D Max",
    },
    {
      value: "Unity",
      label: "Unity",
    },
    {
      value: "Blender",
      label: "Blender",
    },
  ];

  const handleOrderName = (event) => {
    console.info(event);
    setOrderName(event);
  };

  const handleSeasonName = (event) => {
    console.info(event);
    setSeasonName(event);
  };

  const handleCategoryName = (event) => {
    console.info(event);
    setCategoryName(event);
  };

  const handleDateChange = (event) => {
    console.info(event);
    setDateValue(event);
  };

  const handleRequirements = (event) => {
    setRequirements(event);
  };

  const onFormSubmit = (event) => {
    console.info("Form submitted...");
  };
  const onNextButtonClick = () => {
    console.info("Next button clicked");
  };

  return (
    <Container>
      <MyForm onSubmit = {onFormSubmit}>
        <PageTitle>New Order</PageTitle>
        <ProgressIndicator>
          <Dots isActive = {true}></Dots>
          <Dots></Dots>
          <Dots></Dots>
        </ProgressIndicator>
        <br />
        <FormBackground>
          <Subheading>Tell Us a bit more...</Subheading>
          <LabelledIconInput
            label = "ORDER NAME"
            value = {orderName}
            placeholder = "Name"
            onChange = {handleOrderName}
          ></LabelledIconInput>
          <br /> <br />
          <MySpan>
            <LabelledDropdown
              label = "SEASON*"
              selectedValue = {seasonName}
              placeholder = "Select a season"
              options = {seasons}
              onSelectOptions = {handleSeasonName}
            ></LabelledDropdown>
            <LabelledDropdown
              label = "SERVICE CATEGORY"
              selectedValue = {categoryName}
              placeholder = "Select a Category"
              options = {category}
              onSelectOptions = {handleCategoryName}
            ></LabelledDropdown>
          </MySpan>
          <br /> <br />
          <FileUploadComponent
            label = "UPLOAD FILES"
            multiple
          ></FileUploadComponent>
          <LabelledTextArea
            label = "OUTPUT REQUIREMENT"
            value = {requirements}
            placeholder = {null}
            onChange = {handleRequirements}
          ></LabelledTextArea>
          <br />
          <LabelledDateInput
            label = "Expected Delivery Date"
            placeholder = "Select a delivery date"
            dateValue = {dateValue}
            onChange = {handleDateChange}
          ></LabelledDateInput>
          <br />
          <LabelledDropdown
            label = "3D Software"
            width = "100%"
            selectedValue = {software[0].value}
            placeholder = "Select a Category"
            options = {software}
            onSelectOptions = {handleSeasonName}
          ></LabelledDropdown>
        </FormBackground>
        <br />
        <PrimaryButton onClick = {onNextButtonClick}>Next</PrimaryButton>
      </MyForm>
    </Container>
  );
};

export default NewOrder;

Где объявлены/определены компоненты LabelledDropdown и LabelledTextArea? Что такое «Стильные компоненты», которые были скрыты для краткости? stackoverflow.com/help/минимально-воспроизводимый-пример

Drew Reese 06.04.2022 08:40

Компоненты @DrewReese LabelledDropdown и LabelledTextArea присоединены вверху. Я также отредактировал вопрос, указав, где они находятся, и добавил в конце «Стилизованные компоненты». Надеюсь теперь понятно?

Ashar 06.04.2022 08:47
Где в том же файле? Можем ли мы увидеть полный код, как он есть?
Drew Reese 06.04.2022 08:47

Добавлен полный код @DrewReese

Ashar 06.04.2022 08:49
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
4
32
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

что-то вызывает повторный рендеринг, и поэтому он теряет фокус.

У меня была аналогичная проблема внутри вкладок начальной загрузки. Хотя я не мог понять. Но способ, который я сделал, это переменная состояния, которая повторно отрисовывала, я поместил ее в useEffect и вернул фокус на поле ввода. Однако это не очень хороший подход, но, по крайней мере, в этом причина.

Итак, приведенный ниже код - это то, что я сделал. Таким образом, при каждом изменении successOrderReport я бы возвращал поле ввода обратно.

  const searchInput = useRef();

  useEffect(() => {
    searchInput.current.focus();
  }, [successfulorderReport]);

вы можете попробовать это для тестирования, но для вас я бы посоветовал сначала посмотреть, что вызывает повторный рендеринг.

Спасибо @Wahab, на самом деле я потратил некоторое время, пытаясь понять, почему запускается повторный рендеринг. Как видите, в операторе return возвращается простая форма. К сожалению, я не могу использовать здесь useRef, потому что мне не разрешено изменять функциональность LabelledIconInput.

Ashar 06.04.2022 08:37

Вы смогли выяснить, почему он перерисовывается?

Wahab Shah 06.04.2022 08:39

Нет, я еще не мог. Вот почему я спрашиваю здесь.

Ashar 06.04.2022 08:48
Ответ принят как подходящий

Проблема

Проблема в том, что вы объявили все стилизованные компоненты внутри другого компонента React. Каждый раз, когда NewOrder перерисовывает, он повторно объявляет компонент MyForm, который перемонтирует его и все его компоненты поля формы. Любое поле, которое имело фокус, будет перемонтировано и потеряет фокус.

Решение

Определяйте стилизованные компоненты вне метода рендеринга

It is important to define your styled components outside of the render method, otherwise it will be recreated on every single render pass. Defining a styled component within the render method will thwart caching and drastically slow down rendering speed, and should be avoided.

Тело функции весь функционального компонента React является "метод рендеринга".

Объявляйте все стилизованные компоненты отдельно, вне других компонентов React.

const MyForm = styled("form")`
  margin: auto;
`;

const Container = styled("div")`
  ...
`;

const MySpan = styled("span")``;

const PageTitle = styled("h2")`
  ...
`;

const FormBackground = styled("div")`
  ...
`;

const Subheading = styled("h3")`
  ...
`;

const Dots = styled("li")<IDots>`
  ...
`;

const ProgressIndicator = styled("div")`
  text-align: center;
`;

const NewOrder: React.FC<INewOrder> = (props) => {
  ...

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