Задний план

Работая над своим проектом Dice Взломщик, я достиг полусложной остановки, так как застрял на том, как продвигаться вперед. Описание проекта Dice Burglar можно найти в разделе Предыстория моего блога Не зная мелких деталей. Ниже скриншот моего последнего прогресса.

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

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

Однако, когда я перетаскивал любой кубик на любую клетку шахматной доски, она падала на нужную клетку, но она отражалась на всех клетках. другие шахматные доски.

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

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

Первоначальные мысли о функциональности перетаскивания

Первой идеей, которая пришла в голову, был метод грубой силы. В настоящее время все контрольные доски повторно используют один и тот же компонент для рендеринга. Метод грубой силы заключался в создании девяти отдельных компонентов, что подразумевает девять уникальных компонентов (т. е. <CheckerBoard1 />, <CheckerBoard2 /> и т. д.). С девятью уникальными компонентами я бы реализовал логику сравнения, чтобы определить, что место, где падает кубик, должно быть на шахматной доске, отличной от шахматной доски, где он был поднят на уровне родительского компонента. Однако это неэффективно… совсем.

  1. Создавая девять уникальных компонентов, я использую гораздо больше памяти/пространства, чем необходимо, особенно для таких простых вещей, как логика сравнения.
  2. Я нарушаю принцип DRY (не повторяйся). Базовая функциональность каждой шахматной доски остается неизменной: она служит контейнером для всех квадратов шахматной доски и кубиков.

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

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

Встреча ReactNYC

Я был на грани поиска альтернативного метода, пока не посетил мероприятие ReactNYC Meetup. Во время этого мероприятия Нир Кауфман, ведущий мероприятий ReactNYC Meetup, провел демонстрацию воссоздания функции аккордеона. К счастью, он создал эту функцию с нуля, избегая путаницы или предположений о любом потенциальном коде, не показанном аудитории, который может повлиять на саму функцию.

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

Реализация ReactNYC

Выслушав объяснение Нира, ему, по сути, нужно было (и он сделал позже) присвоить каждому родительскому компоненту уникальный идентификатор. Он добился этого с помощью хука React useContext. По сути, useContext() может назначать переменную (например, theme) реквизиту value в поставщике контекста (например, <ThemeContext.Provider/ >), который был создан (например, ThemeContext) в том же файле. Все компоненты, завернутые в оболочку <ThemeContext.Provider />, теперь будут иметь доступ к реквизиту value. Это аналогично оболочке <Provider /> для приложений Redux, где любой компонент, заключенный в нее, будет иметь доступ к Redux store.

Продолжая демонстрацию Нира, он передал значение, представляющее уникальный идентификатор, из реквизита value внутри оболочки провайдера контекста в родительский компонент и в его дочерние компоненты. Используя это значение в своей логике сравнения, компонент будет знать, показывать или скрывать себя при нажатии.

Теоретически собрать все вместе

После того, как Нир закончил свою демонстрацию и замариновал новые концепции, которые я изучил (например, useContext()), я думаю, что у меня есть лучший способ приблизиться к функциональности перетаскивания.

  1. С помощью хука useContext создайте новый контекст.
  2. Оберните каждый компонент шахматной доски новым поставщиком контекста. В реквизите value в каждом провайдере контекста назначьте уникальный ID (скорее всего используйте цифры 1–9).
  3. Создайте новую функцию, которая проверяет опору value, с которой берется кость, до опоры value, где кость бросается. Эти реквизиты value определяются из соответствующей оболочки поставщика контекста. Если оно отличается, дайте кубику упасть. Если нет, не позволяйте этому случиться. Эту логику можно использовать из того, что показано в руководстве по React DnD.

Ключевые вынос

Когда я думал о новой теоретической реализации, на ум пришла фраза «ничего нового под солнцем». Я понял, что назначение уникальных идентификаторов не является новой концепцией (на самом деле, это хлеб с маслом для баз данных/серверной части), но редко встречается во внешнем интерфейсе. Как только я смог абстрагироваться от того, что мне нужно было сделать, все остальное заключалось в манипулировании существующими концепциями в соответствии с потребностями моего проекта. Самой сложной частью было найти те существующие концепции, которые можно облегчить, разветвляясь и изучая новые технологии.