React в плагине Sketch: проблема загрузки исходных данных



Книга React в плагине Sketch: проблема загрузки исходных данных

В этой статье будет подробно рассмотрена проблема загрузки исходных данных при использовании React в Sketch. Она заключается в том, что UI React рендерится без данных Sketch при первом открытии окна плагина.


Мы также рассмотрим одно из возможных решений этой проблемы. В конце статьи есть ссылка на полный демо-репозиторий.


Примечание: плагин реагирует только на слои, а не на страницы. Если запустить плагин с выбранной страницей, он будет рендериться без данных Sketch.


Три компонента плагина с UI React


Плагин Sketch, использующий UI React, можно разделить на три части.


1. Фронтенд


Это веб-браузер (включая DevTools). Это WebView, API которого имитирует API BrowserWindow фреймворка Electron.


WebView “плавает” в отдельном окне поверх UI Sketch. Он обменивается информацией с бэкендом с помощью комбинации window.postMessage (отправка данных) и слушателей событий (получение данных).


2. UI React


Именно в WebView загружается и отображается UI React так же, как при запуске обычного приложения React в веб-браузере.


3. Бэкенд


Это часть плагина имеет связь с данными в документации Sketch. Бэкенд использует API разработчика Sketch.


Бэкенд обменивается информацией с фронтендом с помощью слушателей событий посредством объекта webContents.


Проблема загрузки исходных данных


Загружаемые исходные данные  —  это данные, которые отправляются с бэкенда в UI React после завершения загрузки WebView (фронтенда).


Слишком ранняя отправка данных


Во время разработки плагина я заметил, что при его запуске UI React иногда не получал никаких данных Sketch.


Я попытался выяснить причину. В конце концов разобрался и сформулировал пошаговое объяснение того, что происходит при запуске плагина.


Что происходит при запуске плагина


  1. Бэкенд открывает WebView (фронтенд) и ожидает события did-finish-load, которое должно исходить от WebView.
  2. Фронтенд обнаруживает код JavaScript, который загружает React UI.
  3. React UI прослушивает событие send-data.
  4. Фронтенд выдает событие did-finish-load, сообщая бэкенду, что загрузка завершена.
  5. Бэкенд распознает событие (did-finish-load) и отправляет данные с помощью события send-data.
  6. UI React распознает событие (send-data) и заполняет UI данными события.

Проблема


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


Вследствие этого в UI React не попадают данные Sketch.


Решение


Мы изменили порядок обмена данными. Вместо того, чтобы бэкенд прослушивал и отвечал на событие did-finish-load, мы указали React UI запрашивать данные, как только они будут готовы.


Это потребовало внесения некоторых изменений в код.


my-command.js


В отличие от события did-finish-load, событие get-data не вызывается автоматически WebView. Событие get-data срабатывает только после вызова.


// Меняем
webContents.on('did-finish-load', () => {

// на
webContents.on('get-data', () => {

useSketchData.js


Мы добавили функцию refreshSketchData в хук React, который запускает слушатель событий бэкенда get-data. Это заставляет бэкенд плагина отвечать данными Sketch с помощью события send-data.


import React, {useState, useEffect } from 'react';

const useSketchData = (initialValue) => {
const [sketchData, setData] = useState(initialValue);

useEffect(() => {
const handleSendDataEvent = (e) => {
setData(e.detail.data);
}

window.addEventListener("send-data", handleSendDataEvent);
return () => {
window.removeEventListener("send-data", handleSendDataEvent);
}
}, [])

const setSketchData = (data) => {
window.postMessage('setSelectionName', data);
setData(data);
}

// Добавим это, чтобы запросить данные из "бэкенда"
const refreshSketchData = () => {
window.postMessage('get-data');
}

return [sketchData, setSketchData, refreshSketchData];
}

export default useSketchData;

App.jsx


Мы добавили useEffect, который срабатывает один раз, когда UI React готов к обработке данных Sketch. В useEffect вызываем недавно созданную функцию  —  refreshSketchData.


import React, { useEffect } from 'react';
import useSketchData from '../hooks/useSketchData';

const App = () => {
const [sketchData, setSketchData, refreshSketchData] = useSketchData();

// Срабатывает один раз, когда React UI готов к обработке данных
useEffect(() => {
console.log("refresh data!");
refreshSketchData();
}, []);

const handleButtonClick = (e) => {
const newName = `${sketchData} 🦖`;
setSketchData(newName);
}

return(<div>
<p>{sketchData}</p>
<button onClick={handleButtonClick}>Watch out for the dinosaur!</button>
</div>)
}

export default App;

Вот и все! Изменив порядок загрузки исходных данных, мы предотвратили рендеринг UI React без данных Sketch.


Полная версия демо-репозитория находится здесь.



508   0  

Comments

    Ничего не найдено.