Окно событий еще живо, даже оно удалено - PullRequest
1 голос
/ 28 февраля 2020

enter image description here

Я использовал "billboard.js": "^1.10.2", и react.js

Я искал рекламный щит. Документация js и обнаружил, что onresize(), onresized() прикрепляется к окну, и когда я вызываю chart.destroy () , тогда он удаляет все присоединяемые к окну события, связанные с этой библиотекой.

Я протестировал его без обновления состояния на onresize(), onresized(), он успешно удалил все события, но когда я сделал это с обновлением состояния на onreszie(), onresized(), события все еще были прикреплены к окну. В результате я думаю, что эта проблема возникает не из-за билборда js, а reactjs.

Почему это? Есть идеи?

//...
const [isResize, setIsResize] = useState(false);

const options = {
    onresize(ctx) {
      // "resize" keep prints even chart.destory() is called.
      console.log("resize");
      setIsResize(true);
    },
    onresized(ctx) {
      setIsResize(false);
    },
//...
      <Chart
        className="timelineChart"
        options={options}
        isResize={isResize}
        ref={chartRef}
      />
//...
const options = {
    onresize(ctx) {
      // "resize" is no longer prints when chart.destory() is called.
      console.log("resize");
    },
    onresized(ctx) {

    },
//...

Edit billboardjs resize onresize bug

Ответы [ 2 ]

3 голосов
/ 28 февраля 2020

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

. Вы можете проверить это, проверив логи и заметив эту не очень полезную ошибку:

Предупреждение. Невозможно выполнить обновление состояния React для неустановленного компонента. Это неоперация, но она указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в функции очистки useEffect. на странице 1 (в приложении. js: 13)

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

Мой инстинкт говорит, что здесь Chart.jsx:

  renderChart = () => {
    console.log('render chart');
    const { current } = this.chartRef;
    if (current !== null) {
      this.chartInstance = bb.generate({
        ...this.props.options,
        bindto: this.chartRef.current
      });
    }
  };

Обновлено с полным решением

Я был прав в том, что проблема заключается в Chart.jsx.

Слушатели должны быть подключены при создании и удалении DOM с помощью ДОМ разрушен. Вы не ошиблись, когда впервые решили использовать жизненные циклы React для этой работы, однако я считаю обратные ссылки более полезными, особенно когда некоторые из DOM могут быть уничтожены или созданы во время циклов обновления (вы нет этой проблемы).

Обратный вызов Ссылки могут быть хитрыми, не используйте функции, которые воссоздают каждый рендер (поверьте мне, это головная боль). Обратный вызов вызывается по двум причинам. Во-первых, DOM был создан и передаст вам ссылку на элемент. Во-вторых, DOM был разрушен, поэтому пришло время навести порядок. Если React обнаружит изменение в Ссылке на обратный вызов (то есть вы дадите ему новую), он скажет первой Ссылке на обратный вызов очистить, а второй Ссылке на обратный вызов для инициализации (это головная боль, о которой я говорил). Вы можете избежать этого, используя метод экземпляра.

// Bind to 'this' otherwise 'this' is lost
  setChartRef = (ref) => {
    // Remove listeners
    if (!ref) {
      console.log('no reference');
      this.chartRef.current = null;
      this.destroy();
    }
    // Add listeners
    else {
      console.log('new reference');
      this.chartRef.current = ref;
      this.createChart();
    }
  };

Следующая часть головоломки, которую вы хотите вызвать bb.generate только один раз. Это привело к созданию нескольких слушателей. Поэтому я упростил и переименовал вашу renderChart в createChart

  createChart = () => {
    this.chartInstance = bb.generate({
      ...this.props.options,
      bindto: this.chartRef.current
    });
  };

Наконец, ни один из методов жизненного цикла не является необходимым, поскольку Ссылка на обратный вызов точно сообщает нам, когда создавать диаграмму и когда его уничтожить. Вам может быть интересно, как насчет изменения размера диаграммы? Похоже, об этом позаботятся автоматически? Я мог бы что-то упустить здесь, но если вам нужно обновить диаграмму, используйте this.chartInstance в методе жизненного цикла обновления.

Мои полные модификации здесь:

Edit billboardjs resize onresize bug

2 голосов
/ 28 февраля 2020

onresize на самом деле это событие DOM, оно не является частью рекламного щита или React.

https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event

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

...