Как стать автором
Обновить

Комментарии 27

НЛО прилетело и опубликовало эту надпись здесь

Есть примеры качественной реализации?

Вот здесь я соглашусь.

Более того, если контейнер разрастается до неадекватного количества зависимостей, мы получим ре-рендер всех компонентов, которые берут зависимости из контейнера, при замещении любой одной зависимости в самом контейнере.

А если в контекст будет обернуто вообще все приложение - ре-рендериться будет, точно так же, всё приложение. Так себе решение по части перформанса.

Именно поэтому официальная документация реакта гласит "если можете обойтись без контекста - обойдитесь"

Как частно вы встречались с необходимостью подменять зависимость во время работы вашего приложения? Как правило DI контейнер, будучи однажды сконфигурирован, таким и останется навсегда. Это не динамические данные, которые меняются многократно в процессе выполнения вашего приложения. Т.е. я исхожу из того, что ререндеринга не будет происходить никогда. Если же у вас такой хитрый DI, что зависимости подменяются на лету ежесекундно, то Вам безусловно такое решение не подойдет.

React.FC является deprecated, нужно использовать React.FunctionalComponent

Возможно Вы путаете с React.SFC или я ошибаюсь?

Да, извиняюсь :)

Я, как пользователь и контрибьютор inversify-react, хотел бы сделать акцент на том, что UI вторичен, а DI нужен везде, поэтому и решения типа inversify + интеграция с Реактом выглядят полезнее-надёжнее.

Рад, что удалось привлечь Ваше внимание своей публикацией. Насчет надежнее - использование сторонней библиотеки, какой бы хорошей она ни была, надежнее чем React Context? Чем именно?

Ну сама интеграция с Реактом (проброс IoC контейнер(ов)) идёт всё-равно через React Context – это низкоуровневый апи, от этого никуда не уйти.
Надёжнее – это не в плане, что какой-то там из use'ов отвалится из-за вспышки в верхних слоях атмосферы, а надёжный выбор – не подведёт при усложнении проекта и появлении новых челленджей. Иерархичность, разные виды байндингов/мэппингов, асинхронные подгружаемые зависимости и т.д. Вся эта проблематика обкатана годами на разных платформах и технологиях.

А, ну в этом смысле я безусловно понимаю рамки применимости описанного подхода. Равно как и у подхода с использованием предложенного Вами решения тоже есть свои рамки. Использование решения, которое может гораздо больше требуемого, на случай если это когда-либо понадобится, это здорово, но это не бесплатно, подобные сторонние зависимости усложняют проект, который мог бы быть простым. Любое усложнение должно быть обосновано. Иначе минусы от его внедрения перевесят плюсы.

А чем отличается исходный код от полученного?

В первом случае мы имеем MyComponent имеет прямую зависимость в виде хука useMyHook.

Во втором тоже самое только прямая зависимость от useInjection().

А как в тестах депендонси помог? Точно также будет работать без вашего депендонси.

Я так понимаю вопрос в принципе о том, для чего нужен DI. Как бы тут коротко ответить... Если говорить умными словами, то DI реализует принцип инверсии управления, что уменьшает связанность между модулями/компонентами/сервисами приложения, т.к. они перестают зависеть друг от друга, вместо этого оба зависят от некого абстрактного контейнера и интерфейсов/типов, а не от реализации. Это позволяет нам собирать композицию из таких модулей как нам захочется, а не так как жестко забито в коде. То, что во втором случае компонент зависит от useInjection - не проблема, наша задача отделить модуль верхнего уровня (компонент, отвечающий за UI-презентацию) от модуля нижнего уровня (хук, отвечающий за некую бизнес-логику или получение данных). Т.е. во втором случае мы функцию нашего хука получим используя useInjection как зависимость.

Когда мы тестируем компонент (если конечно речь не об интеграционных тестах), мы хотим именно протестировать сам UI компонент и то, что он корректно отображает данные, которые ему предоставлены, нам не нужно чтобы тест отвалился, скажем, из-за нестабильного интернет-соединения, в случае если наш хук делает http-запрос. Да и даже если наш хук работает криво - тест нашего компонента не должен из-за этого отвалиться - для этого мы должны написать тест нашего хука и пусть отвалится именно он. В тестах мы не будем делать http-запрос, мы заменим наш модуль нижнего уровня Mock-ом, который вернет тестовые данные как если бы они были получены по HTTP

где у вас все это ? как была связанность так и осталась. То что знаете модные слова это хорошо. Но пример не удался. У вас пример с контекстом .. для тестов не надо ничего кроме как обернуть как у вас показано. Для связи с бэком вы все равно так же будете делать прибивать гвоздями хук и оборачивать его просто другим. Это будет по всему коду и наивно полагать что вы не привязываетесь к логике. Если что то изменится вы будете ходить и по всему коду менять свои обертки.
Для тестов существуют моки как вы и сказали если надо затестить то надо мокать запрос...
К сожалению комьюнити фронтенда пытается всегда прыгать выше головы. Зачем вы сюда засунули тс? что бы показать какой вы молодчик и вы в тренде? вы же про другое пытались сказать... Ваш рассказ должен быть лаконичным без мусора.

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

Читайте книги... Преждевременная оптимизация самый большой грех .

где у вас все это ?

Скажите, если я Вам покажу и распишу подробно где, вы готовы вчитаться, вникнуть и увидеть? Или я просто зря потеряю время?

Зачем вы сюда засунули тс? что бы показать какой вы молодчик и вы в тренде?

Мде...

ди предполагает что вы сможете использовать .. то есть внедрять зависимость без изменения кода. Как в вашем примере это будет выглядеть? вам надо будет идти в useInjection и изменять код. Что ДИ такого не подразумевает
https://habr.com/ru/company/devexpress/blog/440552/
сходите почитайте как должно выглядеть то о чем вы пишете.

Думаю если бы вы просто пропсом прокинули то это было бы более лучший варик.

> Вам покажу и распишу подробно где, вы готовы вчитаться, вникнуть и увидеть?
Попробуйте расписать.


Конечно же мне не надо будет идти в useInjection и что-либо там менять. Что ж, попробую на пальцах.

  • В самом первом примере компонент MyComponent явно вызывает функцию useMyHook. Здесь никакого DI нет, зависимость от реализации этой функции явная, подставить что-то другое в компонент мы не можем - он будет вызывать именно ту реализацию функции, от которой зависит.

  • Для реализации DI мы заводим DI-контейнер, который в нашем случае будет храниться в React Context. Компонент больше не будет вызывать useMyHook напрямую. Вместо этого он извлечет значение из контекста (читай - DI-контейнера) по некоторому ключу - там будет функция с нужным нам интерфейсом, а вот как она реализована - компонент и знать не знает.

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

  • В тесте мы положим в наш DI-контейнер не настоящую функцию-хук, а Mock. Для этого мы просто обернем тестируемый компонент в Context Provider, с помощью которого заменим содержимое DI-контейнера. Теперь при выполнении компонент все также извлечет функцию из контейнера по тому же самому ключу, но на месте настоящего хука окажется его фейковая реализация. Никаких изменений в коде компонента или функции useInjection нам для этого делать не потребуется.

На самом деле, думаю что любая библиотека, реализующая DI (упомянутая в обсуждении inversify-react или type-di, да все что угодно) делает ровным счетом то же самое: кладет зависимости в контейнер, а компонент (или что там их будет использовать) - извлекает их из DI-контейнера по определенному ключу. Регистрируя разные реализации зависимостей по одним и тем же ключам можно внедрять ту или иную реализацию, не изменяя код того, кто их использует.

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

Было

import { useMyHook } from ...;

const MyComponent () => {
  ...
  var someResult = useMyHook();
  ...
}

стало

const Container = {
  foo,
  bar,
};

const DIContext = React.createContext(Container);
const useInjection = () => {
  return useContext(DIContext);
};

const MyComponent= () => {
  ...
  const { foo, bar } = useInjection();
  ...
}

в первом случае же у нас тоже обертка ?
или у вас useMyHook(); это не кастомный хук? а хук в виде прямого использования как useContext(DIContext)

А я кажется возможно не туда смотрю. Вы реализовали ДИ по средством самого контекста? то есть контекст === ДИ. А у вас реализация не внедрение самой зависимости а его инструмента.

Ну, давайте так покажу, если foo и bar сбивают с толка.

Было

const someResult = useMyHook();

Стало

const { useMyHook } = useInjection();
const someResult = useMyHook();

А я кажется возможно не туда смотрю. Вы реализовали ДИ по средством самого контекста? то есть контекст === ДИ.

Контекст === DI контейнер. Снаружи мы кладем зависимости в контекст, изнутри - извлекаем зависимости из контекста

Все, спасибо понял )).
Можно еще вопрос. Если повсеместно использовать в проекте не будет ли от этого страдать отладка и поддержка? Появляется же как бы магия. И очень тяжело потом найти источник?
Был опыт использования на больших проектах и долгих.. ? Просто даже в столь не запутаном редаксе на первый взгляд большой проект (очень большой) начинает тонуть в этом плане. А тут вообще будет одна магия.

Да нет тут никакой магии, это обычный React Context

попробуйте написать тоже самое только без понятия ди .. я уверен у вас будет тоже самое .. возможно даже чище

Берите React-ioc и будет вам счастье. На 2х проектах опробован. Один с код сплиттиггом, а второй React Native

Последний коммит в react-ioc 5 лет назад, это подозрительно. Похоже на него забили

На мой взгляд, в статье получился скорее сервис-локатор, чем DI. Хотя в данном случае грань между ними довольно тонкая. Тут даже зависит от того, с какой стороны смотреть. Для всего слоя представления в целом, это DI - весь комплект зависимостей подставляются использующей стороной. Для каждого компонента в отдельности - сервис-локатор, из которого компонент самостоятельно выбирает данные.

DI для отдельного компонента - только через пропсы.

Ндаа, о размер кода и перфоменс тихо плачут в сторонке горючими слезами

Это почему же? Размер кода увеличивается в сравнении с обычным на одну строчку - пишем useInjection перед вызовом хука. На перфоманс влияния вообще нет т.к. контекс никогда за время работы приложения не меняется, следовательно никакого перерендеринга не будет

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации