Pull to refresh

Comments 23

Спасибо за статью. Очень любопытная идея. Лично мне будет интересно понаблюдать за развитием данного инструмента.
Если позволите, оставлю пару предложений для рассмотрения:


  1. Мне кажется, хук useText() мог бы просто возвращать сообщение, вместо того чтобы принимать на вход некий коллбек. Тогда не нужен дополнительный useState() для обновления компонента.
  2. Быть может имеет смысл вместо собственных Route, Switch и т.д. жёстко привязанных к сообщению использовать существующие роутеры (react-router, reach-router) с некой кастомной историей. Таким образом можно разгрузить саму библиотеку, дать возможность ее пользователям работать с привычными инструментами (или без них) и повысить гибкость за счёт ухода от жёсткой завязки на команды в сторону чего-то универсального и аналогичного вебу (history.push('/echo'))
  3. Как вы смотрите на добавление в будущем каких-нибудь dev-тулз для того же тестирования ботов в браузере, например. В самом простом случае это мог бы быть некий компонент-холст, при рендере бота в котором мы получаем можем оценить работу нашего бота (без участия апи телеграмм).
    Заранее прошу прощения, если какое-то из моих предложений противоречит материалу статьи, я мог что-то упустить при беглом прочтении.
  1. Мне кажется useText в виде callback функции идеально здесь подходит, потому что если бы useText возвращал бы сразу текст то тогда пришлось бы каждый раз делать перерендер компанента.
  2. Тоже показалось странным использовать свои собственные Route, Switch и т.д
  3. У меня тоже возникла мысль что наверно должен быть некий простенький эмулятор телеги что-ли чтобы удобно и быстро все тестировать.
если бы useText возвращал бы сразу текст то тогда пришлось бы каждый раз делать перерендер компанента.

Так нам ведь и нужно повторно рендерить компонент, если пришло новое сообщение (иначе как ответить на него?). Если на какое-то конкретное сообщение мы отвечать не хотим, можно просто вернуть null. Любой хук так работает — useParams()/useLocation() в react-router, useSelector() в react-redux, useQuery() в react-query, useSpring() в react-spring. По сути, чуть ли не единственный хук, который принимает и вызывает коллбек — это use(Layout)Effect(), но в этом его суть.

Согласен с вами, так действительно будет удобнее.

1. Согласен, так может быть удобнее, но передача текста в state, не единственный сценарий использования, и вариант с callback более наглядный, что работаем с событием. Можно написать свой хук, который ты предлагаешь, на основе существующего.
function useTextState(initialText?: string) {
    const [text, setText] = React.useState(initialText);

    useText(({ text }) => setText(text));

    return text;
}


2. Хорошая идея, нужно посмотреть на сколько они абстрактны, легко интегрировать и приспособлены ли эти библиотеки работать на сервере, как минимум если они будут хранить историю всех сообщений всех пользователей, то память быстро переполнится. Просто навигация в мессенджере довольно простая, без вложенности, и история нужна скорее всего очень редко, сделали свой простой компонент, чтобы покрыть базовые кейсы.

3. Это супер идея. Я хотел это реализовать до статьи, интегрировать Urban Bot в телеграм веб версию , чтобы работало без авторизации и привязки к API, чтоб можно было прямо в браузере, например, в codesandbox, кодить онлайн, делиться чат ботами с кодом. Если сделаю прототип, то отпишу сюда.

Спасибо за интерес и хорошие предложения.

… но передача текста в state, не единственный сценарий использования

А какой ещё есть?


и вариант с callback более наглядный, что работаем с событием.

Зачастую прелесть хуков в том, что они упрощают реакцию на события за счёт того, что просто повторно рендерят компонент с новым значением. Как я написал в другом комментарии, подавляющее большинство хуков популярных и не очень библиотек делают именно так, мне лично примера с коллбеком в голову не приходит.


Просто навигация в мессенджере довольно простоя, без вложенности и история нужна скорее всего очень редко.

На самом деле боты с меню часто имеют вложенную структуру. По поводу переполнения истории на сервере, ее можно и вовсе не хранить, нам ведь нет смысла реализовывать back/forward логику в телеграмме. А из любого вложенного маршрута (/foo/bar) обычно понятно, как вернуться у предыдущее меню (/foo).


Это супер идея.

Рад, что идея Вам понравилась. Как мне видится, это может быть некий компонент <Sandbox /> внутри которого можно срендерить компонент-бота в самом обычном веб приложении и увидеть простейший экран ввода сообщений и реакции бота) Даже не нужно интегрироваться с телеграммом.

А какой ещё есть?

Например логировать сообщения

useText(({ text }) => console.log(`Пользователь отправил сообщение ${text}`));

Или передавать обработку сообщения выше или в state manager, например, redux.

function Component({ handleTextMessage }) {
    useText(({ text }) => handleTextMessage(text));
    // или
    useText(({ text }) => dispatch(addTodo(text)));

    // ...
}


По поводу роутера уже в работе задача по поддержке router params, я добавил твое предложение и ссылку на комментарий в issue github.com/urban-bot/urban-bot/issues/109.

Даже не нужно интегрироваться с телеграммом.

Я имел в виду, чтобы взять уже готовую веб версию чата, на базе Telegram, которая в open source, чтобы не писать свой. Может будет проще свой компонент написать как ты предложил, в любом случае спасибо за хорошие наводки.

Для логирования, записи в Редакс и других эффектов есть useEffect()

> нам ведь нет смысла реализовывать back/forward логику в телеграмме

Очень спорно. В своем боте реализовал поддержку истории со многоуровневыми меню и переходами между разными «экранами», пользователи, вроде бы, довольны.

Я, правда, использую кастомную клавиатуру, а не инлайн-кнопки, но то такое.

В общем, юз-кейсы могут быть абсолютно непредсказуемыми и утверждать, что чего-то не надо — опрометчиво.
Не знаю, но есть ощущение, что на $mol это сделать проще)

На JS это сделать проще.

Спасибо за модуль, начал использовать чуть ли не с первого релиза на npm. Я просто тогда офигел, на сколько это качественный продукт даже в бете. На UrbanBot реализация моего бота оказалась раза в 4 проще, чем то, что я писал ранее, даже с другими хорошими библиотеками.

Взаимное спасибо от команды проекта, нам очень приятно слышать. Такие слова мотивируют нас работать над проектом. Мы вас помним, вы третий человек, кто поставил звездочку нашему репозиторию на github, вторыми двумя были мы сами, и на тот момент мы нигде проект не выкладывали. В тот момент нас это очень взбодрило.
Можно ли сделать бота, который будет сгружать фото\видео в гуглдиск\дропбокс\мегу\вставьте_своё_хранищиле?
Ну то есть добавить его в чат-группу, а он оттуда пусть всё грабит и бэкапит
Есть в ближайших планах написать такого бота.

Я уже писал демку telegram-file-hosting-urban-bot.
Бот скачивает картинку, которую кинул пользователь в чат с ботом, сохраняет в папку проекта и снова отсылает ее в чат уже от имени бота.
Осталось прикрутить загрузку на хостинг.
Код черновой и немного недоделанный, я не рассчитывал, что кому-то буду его скидывать, но может вам будет полезно.

Можно, в планах добавить хук или утилиту, чтобы легко получать ссылку на файл или скачивать на файловую систему, если юзер что-то прислал боту, например, в Telegram вроде надо три разных запроса подряд отправить, чтобы получить ссылку, а так функцию вставил и будет работать. Сейчас можно так сделать, но нужно вручную к Telegram API обращаться

Что-то например:

import { downloadFile, getDownloadURL } from '@urban-bot/kit';

function Component {
    useFile((file) => downloadFile(file, '/files'));

    useImage((image) => {
        const imageURL = getDownloadURL(image);
    });

   // ...
}

Возможно эту часть надо запрятать не в специальные функции, а во внутренности bot-instance'ов. Потому что у вас так получается, что все муки выбора нужных хуков падут на программиста. Хотя муки выбора нужных компонентов вы с него сняли реализацией стандартных.

Согласен, эти функции скорее для единого интерфейса, под капотом должен вызываться метод активного bot-instance'ов. Можно будет брать их из хука, чтобы внутри сами получали активный bot из контекста.

import { useDownloadFile } from '@urban-bot/core';

function Component {
    const downloadFile = useDownloadFile();

   // ...
}


Ребята, вы опоздали на год! Ну или я просто вас не искал тогда когда мне это было надо и сидел живал кактус.


Потенциал у библиотеки просто огромнейший! Сюда можно подключить хоть половину стека реакта и заиметь очень много фичей, которых тупо не хватает в императивном стиле.


Я писал небольшого по нынешним меркам бота и честно говоря реализовывать логику формочки на telegraf — застрелиться можно. Это просто ужас. В общем муки, муки, муки.


Пока я делал этого бота, пытался вспомнить хоть одно упоминание декларативного описания ботов, но не в виде no code сервисов, а в виде библиотек-фреймворков и нифига ни на одном языке вспомнить не смог.


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

А теперь про технику.


Честно говоря внутренний API у вас сильно спорный. Из проблем которые вижу прямо сейчас:


  1. В документации не описано задание собственного хранилища сессий. Для работы по принципу stateless и например деплоя на heroku или vercel, который вы сами знаете как работает, это палка в колесо.
  2. Названия методов и параметров у вас спорное… Это конечно дело творца, но получается очень перегружено и многословно.
  3. useText, useVideo и так далее — по смыслу слова честно говоря не подходит от слова совсем. Конечно хорошо иметь приемственность, но api из реакта вы немного не соблюдаете. По сути все эти штуки это коллбеки, возможно их стоило бы назвать onTextAction((text) => .. do smth ..). И сразу же вопрос, куда вы дели зависимости коллбеков :)
  4. Вы не сможете сделать прямо совсем совсем унивирсальные компоненты. Очевидно что вы вдохновлялись telegram'ом, но наличие useDice в core очень и очень сильно напрягает. Так же вопрос универсальности встаёт в свете того, что например кто-то сделает компонент Sticker для телеграма, а потом другой человек сделает этот же компонент для VK. Будет ли теперь Sticker влезать в core или он будет разделён на 2 platform-specific пакета? Или может вообще третий человек сделает третий пакет который объединяет обе реализации Sticker в одном компоненте в зависимости от контекста запуска. В общем тут я бы очень хотел узнать вашу позицию относительно "унификации" вашего API так, чтобы на него реально можно было как на кости накидывать мясо в виде разных платформ.
  5. Вытекает из 4. Что будет если я использую компонент который не поддерживается в другой платформе? Мне вылетит какая-то ошибка или произойдёт какой-то фоллбек или что вообще произойдёт?

А теперь хотелочки:


  1. hot-reload. После работы в вебе этой функции не хватает примерно в каждом проекте. С реализацией сессий например через файлы, можно будет и nodemon запускать. Но это опять же не совсем то, что хотелось видеть.
  2. Более декларативный роутер. Тот который вы сделали сейчас очень даже хорош. Но он у вас немного vendor-lock'нутый получается. Уже есть много разных реализаций разных роутеров на фронте и под каждую задачу удобен свой. На вашем месте я бы реально реализовал свой history api со своим HOC, который бы подменял контекст пользователя на то, что ему надо.
  3. Более компонентый bot api. Это касается сейчас наверное реализации самих bot-instance'ов, а конкретнее телеги и слака. И у того, и у того есть как longpoll, так и webhook, а у слака ещё и websocket'ы. Так вот реализацию longpoll и webhook желательно бы вынести как можно в более отдельный комопонент. Мне потому что например нравится скармливать события боту ручками. А ещё когда вы его вынесете можно будет его легче и точнее конфигурировать.
  4. Тестирование. Выше говорили про визуальное тестирование. Я бы хотел предложить вам сфокусироваться сначала не на визуальной оболочке ботов, всё равно тестировать надо на реальном телеграме, а на каком-то решении для программного тестирования.
  5. Ошибки. Кажется уже сейчас можно реализовать отлов ошибок с помощью componentDidCatch, но всё же хотелось бы освещение этого момента в документации и официальной поддержки этого механизма.

Дальше уже пожелания так по-мелочи: доку получше, интеграций побольше и всякое такое — это всё приходит со временем и обязательно появится.


Продублирую мысль из своего предыдушего комментария: "То что вы уже сделали очень и очень круто. Жду не дождусь когда смогу попользоваться".

Чуть позже отвечу по пунктам, замечания дельные. Как минимум hot reload уже реализован в стартере, линт девелопмент, билд скрипты, возможно надо было подробнее описать

1. Согласен, надо как минимум пример написать.
2. Здесь думаю лучше обсуждать конкретные случаи с предложением лучших вариантов, желательно на гитхабе.
3. Это именно хуки, так как используют useBotContext под капотом. useOnText наверное лучше подошло бы, но не уверен, что сейчас стоит менять имя после релиза.
4. Про dice очень хорошо заметил, я планировал его в random для большей универсальности переименовать, в коде даже туду есть, но скорее всего ты прав, лучше вынести в телеграм пакет. Пока тактика такая, что если что-то может встретиться более чем в одном мессенджере будет в core, а если реально специфичная вещь, то будет в соответствующем пакете.
5. Сейчас будет просто варнинг, что такой то мессенджер не поддерживает такой тип сообщения.

1. Уже есть в create-urban-bot.
2. Да, было бы круто прикрутить как минимум react-router, глянем в эту сторону.
3. Не совсем понял, лучше создать issue с примером.
4. Согласен, это важнее.
5. С ошибками все как в реакте, но в доках надо прописать, согласен.
Sign up to leave a comment.

Articles