В этой статье будет подробно рассмотрена проблема загрузки исходных данных при использовании 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.
Я попытался выяснить причину. В конце концов разобрался и сформулировал пошаговое объяснение того, что происходит при запуске плагина.
Что происходит при запуске плагина
- Бэкенд открывает WebView (фронтенд) и ожидает события
did-finish-load
, которое должно исходить от WebView. - Фронтенд обнаруживает код JavaScript, который загружает React UI.
- React UI прослушивает событие
send-data
. - Фронтенд выдает событие
did-finish-load
, сообщая бэкенду, что загрузка завершена. - Бэкенд распознает событие (
did-finish-load
) и отправляет данные с помощью событияsend-data
. - 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.
Полная версия демо-репозитория находится здесь.
Читайте также:
- Адаптивный фавикон для современных веб-приложений на React
- Как запустить сайд-проект за 10 дней
- Создание компонентной дизайн-системы UI
Читайте нас в Telegram, VK и Дзен
Перевод статьи Fredrik Ward: How to use React in your Sketch plugin — The Problem with Initial Data Load