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

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

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

Как я уже сказал, мне очень сложно это исправить, так как я не могу воссоздать его, поэтому любая помощь будет очень признательна. Я использую React Hooks и 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 && (
        <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] && (
        <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) => {

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

Сторожевые хлебные крошки

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

Форма изображения


person Andrew Irwin    schedule 17.08.2020    source источник
comment
Я предполагаю, что это связано с доступом к DOM вне жизненного цикла React, особенно в районе props.disabled и document.getElementById. Вы можете добавить контекст для продвижения состояния и позволить React обрабатывать состояние DOM — kentcdodds.com/blog/how-to-use-react-context-efficiently   -  person nrako    schedule 24.08.2020
comment
Можете ли вы добавить остальную часть кода класса компонента? Или, по крайней мере, ваша реализация setFieldValue? Как ни странно, чаще всего, когда проблемы в React возникают только иногда, это связано с состоянием гонки, чаще всего с setState.   -  person Zachary    schedule 24.08.2020
comment
почему вы устанавливаете значение реквизита? props.setFieldValue( "parentSignature", sigCanvas.current.getTrimmedCanvas().toDataURL("image/png") );   -  person Nidhi Dadiya    schedule 25.08.2020
comment
@nrako Спасибо, я проверю, не вызывает ли проблема props.disabled.   -  person Andrew Irwin    schedule 25.08.2020
comment
@Zachary У меня уже есть реализация, добавленная для setFieldValue во фрагменте формы выше. Спасибо за ваш комментарий.   -  person Andrew Irwin    schedule 25.08.2020
comment
@NidhiDadiya Я устанавливаю props.SetFieldValue, когда я передаю setFieldValue из компонента формы выше. Спасибо за ваш комментарий.   -  person Andrew Irwin    schedule 25.08.2020


Ответы (2)


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

Возможно, вы устанавливаете состояние из несмонтированного элемента DOM (холста). Это происходит не постоянно, потому что это состояние гонки. Вы должны проверить, действительно ли холст 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")
    );
  }
};

// ...
person jaredpalmer    schedule 25.08.2020
comment
Спасибо за ваш ответ, и спасибо за то, что написали такую ​​фантастическую библиотеку, которая делает мою разработку невероятно легкой! это в сочетании с да;) Я попробую ваш ответ и, надеюсь, это сработает. Это было довольно неприятно, чтобы прибить его, так как это случается только иногда на 10%. Я назначу награду в размере 50, поскольку срок ее действия скоро истечет, только за вашу работу над Formik! Я отмечу ответ как принятый, если он сработает для меня. :) - person Andrew Irwin; 25.08.2020
comment
Теперь я могу последовательно воссоздать сбой. По-прежнему возникает сбой, если клавиатура все еще открыта после того, как пользователь только что набрал parentName, а затем они сразу же переходят к рисованию на панели для подписи. Мне придется придумать способ отключить панель для подписи, пока клавиатура не будет убрана. - person Andrew Irwin; 26.08.2020

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

Спасибо :)

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

person Andrew Irwin    schedule 28.08.2020