Приложение React иногда вылетает при открытии react-signature-canvas

#html #reactjs #canvas #formik #signaturepad

#HTML #reactjs #canvas #formik #панель подписи

Вопрос:

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

Похоже, это происходит только на действительно дешевых планшетах Android. У меня есть страница с формой, где пользователь заполняет детали, проблема возникает сразу после того, как они ввели свое имя в текстовое поле, а затем, как только они нажимают на react-signature-canvas , чтобы начать рисовать свою подпись, приложение вылетает (не всегда вылетает). в прошлом, я думаю, сбой был вызван тем, что клавиатура все еще была открыта, когда пользователь пытался начать рисовать на панели подписи.

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

Форма:

 <h2>Guardian Full Name</h2>
            <MyTextField
              label="Guardian Full Name"
              name="parentName"
              required
            />
            <ErrorMessage
              component={"div"}
              className={"termsConditionText error"}
              name={"parentSignature"}
            />

            <SignaturePad setFieldValue={setFieldValue} />
  

Панель подписи:

     import React, { useRef, useState } from "react";
import { Button } from "semantic-ui-react";
import "../../pages/SignDisclaimerForm/SignDisclaimerForm.css";
import "./signaturePad.css";
import SignatureCanvas from "react-signature-canvas";

export const SignaturePad = props => {
  const [canvasImageUrl, setCanvasImageUrl] = useState([
    props.parentSignature || ""
  ]);
  let sigCanvas = useRef();

  const clearCanvas = () => sigCanvas.current.clear();
  const saveCanvas = async () => {
    if (sigCanvas.current.isEmpty()) return;
    document.getElementById("parentName").blur();

    props.setFieldValue(
      "parentSignature",
      sigCanvas.current.getTrimmedCanvas().toDataURL("image/png")
    );
    setCanvasImageUrl(
      sigCanvas.current.getTrimmedCanvas().toDataURL("image/png")
    );
  };

  return (
    <div>
      {!props.disabled amp;amp; (
        <div>
          <h2 style={{ marginLeft: "5%" }}>Guardian Signature</h2>
          <div className={"sigContainer"}>
            <SignatureCanvas
              ref={sigCanvas}
              canvasProps={{ className: "sigPad" }}
              onEnd={saveCanvas}
            />
          </div>
          <Button
            style={{ marginLeft: "5%", marginTop: "2%", marginRight: "2%" }}
            type={"button"}
            onClick={clearCanvas}
            children={"Clear"}
          />
          <br />
          <br />
        </div>
      )}

      {canvasImageUrl[0] amp;amp; (
        <div className={"signatureDisplay"}>
          <img
            src={canvasImageUrl}
            alt={"Guardian Signature"}
            style={{ height: "100%", width: "100%" }}
          />
        </div>
      )}
    </div>
  );
};
  

Отчет о проблеме Sentry также приведен ниже.

Заголовок проблемы:

 TypeError HTMLCanvasElement.r(src/helpers)
error
Cannot read property 'push' of undefined
  

Текст проблемы:

../../src/helpers.ts в HTMLCanvasElement.r в строке 85:17

  }
  // Attempt to invoke user-land function
  // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
  //       means the sentry.javascript SDK caught an error invoking your application code. This
  //       is expected behavior and NOT indicative of a bug with sentry.javascript.
  return fn.apply(this, wrappedArguments);
  // tslint:enable:no-unsafe-any
} catch (ex) {
  ignoreNextOnError();
  withScope((scope: Scope) => {
  

Хлебные крошки:

Сторожевые панировочные сухари

Вот как выглядит форма:

Изображение формы

Комментарии:

1. Я предполагаю, что это связано с доступом к DOM за пределами жизненного цикла React, в частности вокруг props.disabled и document.getElementById . Вы могли бы рассмотреть возможность добавления контекста для улучшения состояния и позволить React обрабатывать состояние DOM — kentcdodds.com/blog/how-to-use-react-context-effectively

2. Можете ли вы добавить остальной код класса компонента? Или, по крайней мере, вашей реализации setFieldValue ? Как ни странно, я чаще всего обнаруживаю, что проблемы в React возникают только иногда , это связано с состоянием гонки, чаще всего с setState .

3. почему вы устанавливаете значение props? props.setFieldValue( "parentSignature", sigCanvas.current.getTrimmedCanvas().toDataURL("image/png") );

4. @nrako Спасибо, я проверю, что вы, чтобы увидеть, вызывает ли props.disabled проблему.

5. @NidhiDadiya Я устанавливаю реквизиты. SetFieldValue, которое я передаю setFieldValue из компонента формы выше. Спасибо за ваш комментарий.

Ответ №1:

Автор Formik здесь…

Возможно, вы устанавливаете состояние из размонтированного элемента DOM (canvas). Это происходит не всегда, потому что это условие гонки. Вы должны проверить, действительно ли смонтирован canvas ref , прежде чем использовать методы для него в ваших обратных вызовах.

 // ...

const sigCanvas = useRef(null);

const clearCanvas = () => {
  if (sigCanvas.current != null) {
    sigCanvas.current.clear();
  }
};

const saveCanvas = async () => {
  // Ensure that the canvas is mounted before using it
  if (sigCanvas.current != null) {
    if (sigCanvas.current.isEmpty()) return;
    document.getElementById("parentName").blur();

    props.setFieldValue(
      "parentSignature",
      sigCanvas.current.getTrimmedCanvas().toDataURL("image/png")
    );
    setCanvasImageUrl(
      sigCanvas.current.getTrimmedCanvas().toDataURL("image/png")
    );
  }
};

// ...
  

Комментарии:

1. Спасибо вам за ваш ответ и спасибо вам за написание такой фантастической библиотеки, которая делает мою разработку такой фантастически легкой! это в сочетании с yup 😉 Я попробую ваш ответ и, надеюсь, это сработает. Было довольно сложно разобраться с этим, так как это случается иногда только в 10% случаев. Я назначу вознаграждение в размере 50, поскольку срок его действия истекает, только за вашу работу над Formik! Я отмечу ответ как принятый, если он сработает для меня. 🙂

2. Теперь я могу последовательно воссоздавать сбой. По-прежнему появляется сбой, если клавиатура все еще открыта после того, как пользователь только что ввел ParentName, тогда они сразу переходят к рисованию на панели подписи. Мне придется придумать какой-нибудь способ отключить панель подписи, пока клавиатура не будет отключена.

Ответ №2:

Спасибо всем, кто мне помог, я действительно это оценил. В конце концов, чтобы устранить проблему, я просто установил зеленую кнопку, которую пользователь должен был нажать, чтобы открыть панель подписи. Тот факт, что пользователь должен нажать кнопку открыть, дает клавиатуре достаточно времени для полного отключения, прежде чем пользователь начнет рисовать на панели подписи.

Спасибо 🙂

Панель подписи с демонстрационной кнопкой открытия