Доступность — это не «фишка» и не «дополнительная опция». Это базовое качество современного веб-приложения. Если ваш интерфейс не работает с клавиатурой или не читается экранными читалками, значит, он недоступен для миллионов пользователей
Полностью согласен.
А такой вопрос есть, вы сталкивались с тем, что бы для тестирования вам необходимо было еще все это обвешивать тестовыми идишниками?
Просто для примера, я смотрю на ваш пример и что-то с лету в голову не приходит кейса, когда что-то подобное было нужно...
К слову о ненужных зависимостях, моя практика утверждает обратное: если их удалить, то линтер и правда не ругается, но высота третьего блока не будет обновляться динамически.
Вы про пример?
Не совсем поняла эту часть — «когда работаешь с хуками нельзя конфигурировать их литералами». Уточните, пожалуйста.
Вы в зависимости useLayout прокинули литерал, поэтому у вас в примере при каждом рендере все это устанавливалось и снималось постоянно
Я бы на вашем месте пример все таки отредактировал. Вдруг кто-то подумает, что у вас что-то такое в продакшене.
Тут два момента. Первый, когда работаешь с рефами нет никакого смысла прокидывать их в зависимости (у вас этого конечно нет, но ваше решение вдохновлено чем-то подобным). Линтеры об этом знают, поэтому "кричать" не будут. И второй, когда работаешь с хуками нельзя конфигурировать их объектными литералами. В вашем примере, каждый рендер приводит к отработке useLayoutEffect, что вредно.
И есть еще один момент. Вы сделали вот такую штуку:
Это означает, что при каждом изменении размера у вас перерисовывается весь компонент. Это, конечно, мелочь, если размеры меняются редко, но все таки смысла для ряда случаев в этом нет никакого.
Так я же написал почему. Мы имеем число 0 для которого Boolean(0) возвращает false. Иными словами Boolean только что отсеял значение с типом number. Т.е. для number Boolean не является корректным предикатом типа.
Но вообще, я выше описал общий случай почему Boolean в принципе не является предикатом типа.
Иными словами тут всегда выход - это boolean, а для предиката типов должна быть ясная связь между типом входного значения и типом выходного. Поэтому при использовании Boolean и возможны ошибки типа той, что в примере из статьи.
В этом примере мы ожидаем, что тип arr будет number[], но на самом деле получаем (number | undefined)[], потому что TypeScript не может точнее определить тип возвращаемого значения. Это неудобно: ты точно знаешь, что в рантайме undefined не будет, но в типах обязан это учитывать
Нет. Все обстоит не так. Начиная с версии 5.5 Typescript корректно выводит предикаты типов. Но должны соблюдаться два условия:
1. Типа предикат должен возвращать тип Т, когда функция возвращает true
2. Когда функция возвращает false входной параметр точно не Т
А что мы видимо в предложенном примере? Когда у нас значение 0, то Boolean возвращает false. Поэтому Boolean не является корректным предикатом типов для number. Поэтому typescript и не меняет number | undefined на number. И правильно делает, потому что тогда бы разработчики допускали ошибку в коде.
После того как в начале дан пример в котором варианты 1. это селектор и 1. это уникальный селектор представляется, что статья морально устарела лет этак на 5 минимум.
Ролевые селекторы позволяют искать элементы по их роли на странице, что делает их более стабильными и предсказуемыми, однако, этого все ещё недостаточно.
Одной из основных проблем с использованием ролевых селекторов является их ограниченность. Они не могут быть использованы для поиска элементов по их атрибутам или содержимому, что может привести к непредсказуемым результатам.
Также, у них есть всё та же проблема, что и у классовых селекторов - мы можем наткнуться на коллизию элементов.
Ролевые селекторы позволяют искать элементы так как если бы их искал человек. Поэтому, если смотреть с этой стороны, то получается следующее. Второй абзац в принципе не нужен, т.к. элемент и не должен искаться по атрибуту. А вот про содержимое я не понял.
И второе, коллизия элементов говорит о том, что с точки зрения семантики элемент спроектирован плохо, поэтому коллизия и возникает. Иными словами возникает ситуация когда ассистивная технология не может один элемент отличить от другого.
Поэтому, основной проблемой мне видится высокий порог вхождения для использования таких селекторов, а вовсе не их ограниченность.
Я имею в виду, что resolve типизирован? Т.е. если ему передать строку 'profile', то во первых он подскажет саму строку, а во вторых предложит объект параметров, который соответствует данному маршруту?
А то я не очень понимаю, если вы импортируете из пакета resolve, то кто следит за типизацией параметров?
resolve('profile', user_id=123)
Где происходит связывание псевдонима и соответствующего ему типа объекта параметров? Из обозначенного вами кода я не очень понял как это все типизируется из коробки?
Разумеется получилось сильно проще чем у вас. Плюс я отталкивался от утилит типов и духа самого реакт роутера, поэтому не стал добавлять того, чего там нет. И типы ослаблены примерно так же как и у самого React Route. Но у меня и не стояло задачи поддерживать огромное количество страниц как в вашем случае.
п.с.: код написал, что бы схематично обозначить сам подход. Он может быть в чем-то не до конца точен.
А вы зачем все это сделали в таком виде? Т.е. зачем тут все эти развернутые исходники? Очень неудобно все это читать, но больше всего непонятно именно зачем?
Я рандомно, листая, остановился на одном из таких кусков и не очень понял зачем это показывать. У статьи же явно какие то другие цели, чем обсуждать это. Или все таки не против обсудить?
Первый же вопрос по форме, почему это называется Click?
Дальше, просто...
1. Если у вас ForceGraph мэм-ный компонент, то в useCallback нужно оборачивать все, а не один handleNodeClick. В этом просто нет никакого смысла.
2. Так как у вас ForceGraph не зависит от clickNodes, и параметризуется только обработчиками то получается Реакту вообще нет никакого смысла постоянно перерисовывать/пересчитывать этот компонент при изменении обработчиков. Он должен быть отрисован один раз, а потом уже заниматься своей работой никак не перерисовывая постоянно ваш Click
3. Все для чего нужен перерендер Реактом - это работа с элементом формы, чекбосом. Поэтому делать clickNodes состоянием компонента нет никакого смысла и даже вредно. Его изменения не должны влиять на рендер.
4. При работе с управляемым чекбоксом лезть в объект события нет никакой необходимости. Поэтому если есть желание тоже можно добавить обработчик через useCallback. А можно и не добавлять, т.к. в вашем случае чекбокс не библиотечный компонент.
В результате мы получили компонент, которые перерисовывается только по чекбоксу. Что тоже можно убрать, например, добавив контекст.
И вот, возвращаемся к тому с чего я начал. Я вот не очень понимаю, зачем было выкладывать такое? Лучше же просто расписать человеческим языком и все. Отвлекаться на такой код и тем более тратить на него место, по моему, контрпродуктивно. Или все таки была цель показать как именно Реакт использовать для таких задач?
Не-е, это я вставил, меня отвлекли и я упустил возможность исправить. Разумеется там не должно быть никакого length.
for (let i = 0, max = array.length; i < max; i++) {
console.log(array[i]);
}
{
const max = array.length
for (let i = 0; i < max; i++) {
console.log(array[i]);
}
}
А мне еще другое любопытно. Описанный пример загрязняет область видимости переменными цикла. Что не очень удобно, если имеются несколько, например, идущих подряд циклов. И что тогда автор делает, придумывает разные имена или использует какой-нибудь такой подход, что бы сохранить оптимизацию производительности:
for (let i = 0, max = array.length; i < length; i++) {
console.log(array[i]);
}
или
{
const max = array.length
for (let i = 0, max = length; i < length; i++) {
console.log(array[i]);
}
}
Не знаю. Когда слышу всякое про х10 производительности там, много дешевой колбасы что бы "накормить" десятки тысяч тут, и всякое про нужно для резюме и важность количества над качеством сразу представляется в первую очередь работа по "перекладыванию json-ов".
Да нет, я вопрос поставил именно так, что нужно именно согласие и понимание, что усилия идут на дешевую работу. То, что появился инструмент который может создавать много дешевой дряни вовсе не означает, что это нужно делать.
Во-вторых, эти "5-6 раз” могут быть от 2 до 10 на самом деле. И если ты инструмент освоил хорошо, то можешь скакнуть в продуктивности повыше, и тогда денег на час занятости у тебя будет больше(ну или больше свободного времени), а если освоил плохо, то да, твой час внезапно подешевел.
Это же не так работает. Обычный работник работает за оклад. В редких случаях еще есть премия. Все. Если ваша работа упрощается настолько, что ее может делать ИИ-шка, то такой работник в принципе не нужен. Его можно уволить. Это с одной стороны. А с другой, вот эти вот школы, курсы и т.п., которые сейчас на конвейере создают таких вот специалистов будут так же создавать давление на ЗП.
Но, все это имеет смысл, если все упирается только в количество. Вот вы тоже почему то именно на это акцент сделали.
Типа до сих пор этого не произошло?
Так вы же его буквально задаете - поэтому это литерал.
А в каких случаях это `[block1Ref.current, block2Ref.current] ` имеет смысл?
Полностью согласен.
А такой вопрос есть, вы сталкивались с тем, что бы для тестирования вам необходимо было еще все это обвешивать тестовыми идишниками?
Просто для примера, я смотрю на ваш пример и что-то с лету в голову не приходит кейса, когда что-то подобное было нужно...
Вы про пример?
Вы в зависимости useLayout прокинули литерал, поэтому у вас в примере при каждом рендере все это устанавливалось и снималось постоянно
Я бы на вашем месте пример все таки отредактировал. Вдруг кто-то подумает, что у вас что-то такое в продакшене.
Тут два момента. Первый, когда работаешь с рефами нет никакого смысла прокидывать их в зависимости (у вас этого конечно нет, но ваше решение вдохновлено чем-то подобным). Линтеры об этом знают, поэтому "кричать" не будут. И второй, когда работаешь с хуками нельзя конфигурировать их объектными литералами. В вашем примере, каждый рендер приводит к отработке useLayoutEffect, что вредно.
И есть еще один момент. Вы сделали вот такую штуку:
Это означает, что при каждом изменении размера у вас перерисовывается весь компонент. Это, конечно, мелочь, если размеры меняются редко, но все таки смысла для ряда случаев в этом нет никакого.
п.с.: за оптимизм пальчик вверх я вам поставлю.
Так я же написал почему. Мы имеем число 0 для которого Boolean(0) возвращает false. Иными словами Boolean только что отсеял значение с типом number. Т.е. для number Boolean не является корректным предикатом типа.
Но вообще, я выше описал общий случай почему Boolean в принципе не является предикатом типа.
Если более обще посмотреть. То имеем:
Иными словами тут всегда выход - это boolean, а для предиката типов должна быть ясная связь между типом входного значения и типом выходного. Поэтому при использовании Boolean и возможны ошибки типа той, что в примере из статьи.
По моему, стоит задиприкейтить {} потому что сейчас это пережиток прошлого.
Нет. Все обстоит не так. Начиная с версии 5.5 Typescript корректно выводит предикаты типов. Но должны соблюдаться два условия:
1. Типа предикат должен возвращать тип Т, когда функция возвращает true
2. Когда функция возвращает false входной параметр точно не Т
А что мы видимо в предложенном примере? Когда у нас значение 0, то Boolean возвращает false. Поэтому Boolean не является корректным предикатом типов для number. Поэтому typescript и не меняет number | undefined на number. И правильно делает, потому что тогда бы разработчики допускали ошибку в коде.
После того как в начале дан пример в котором варианты 1. это селектор и 1. это уникальный селектор представляется, что статья морально устарела лет этак на 5 минимум.
Ролевые селекторы позволяют искать элементы так как если бы их искал человек. Поэтому, если смотреть с этой стороны, то получается следующее. Второй абзац в принципе не нужен, т.к. элемент и не должен искаться по атрибуту. А вот про содержимое я не понял.
И второе, коллизия элементов говорит о том, что с точки зрения семантики элемент спроектирован плохо, поэтому коллизия и возникает. Иными словами возникает ситуация когда ассистивная технология не может один элемент отличить от другого.
Поэтому, основной проблемой мне видится высокий порог вхождения для использования таких селекторов, а вовсе не их ограниченность.
Я имею в виду, что resolve типизирован? Т.е. если ему передать строку 'profile', то во первых он подскажет саму строку, а во вторых предложит объект параметров, который соответствует данному маршруту?
А как это работает на ТС, можно ссылку?
А то я не очень понимаю, если вы импортируете из пакета resolve, то кто следит за типизацией параметров?
Где происходит связывание псевдонима и соответствующего ему типа объекта параметров? Из обозначенного вами кода я не очень понял как это все типизируется из коробки?
Я использовал роутеровский PathParam. Что-то типа:
И так как это все равно на выходе всегда строка не перегружал типами.
Любопытно получилось. Было интересно.
Я когда столкнулся с похожей проблемой пошел немного другим путем. Но в основе тоже решил сделать дерево маршрутов.
А вот генерировать его решил из конфигурации:
Скрытый текст
Разумеется получилось сильно проще чем у вас. Плюс я отталкивался от утилит типов и духа самого реакт роутера, поэтому не стал добавлять того, чего там нет. И типы ослаблены примерно так же как и у самого React Route. Но у меня и не стояло задачи поддерживать огромное количество страниц как в вашем случае.
п.с.: код написал, что бы схематично обозначить сам подход. Он может быть в чем-то не до конца точен.
А вы зачем все это сделали в таком виде? Т.е. зачем тут все эти развернутые исходники? Очень неудобно все это читать, но больше всего непонятно именно зачем?
Я рандомно, листая, остановился на одном из таких кусков и не очень понял зачем это показывать. У статьи же явно какие то другие цели, чем обсуждать это. Или все таки не против обсудить?
Пример:
Скрытый текст
Первый же вопрос по форме, почему это называется Click?
Дальше, просто...
1. Если у вас ForceGraph мэм-ный компонент, то в useCallback нужно оборачивать все, а не один handleNodeClick. В этом просто нет никакого смысла.
2. Так как у вас ForceGraph не зависит от clickNodes, и параметризуется только обработчиками то получается Реакту вообще нет никакого смысла постоянно перерисовывать/пересчитывать этот компонент при изменении обработчиков. Он должен быть отрисован один раз, а потом уже заниматься своей работой никак не перерисовывая постоянно ваш Click
3. Все для чего нужен перерендер Реактом - это работа с элементом формы, чекбосом. Поэтому делать clickNodes состоянием компонента нет никакого смысла и даже вредно. Его изменения не должны влиять на рендер.
4. При работе с управляемым чекбоксом лезть в объект события нет никакой необходимости. Поэтому если есть желание тоже можно добавить обработчик через useCallback. А можно и не добавлять, т.к. в вашем случае чекбокс не библиотечный компонент.
Скрытый текст
В результате мы получили компонент, которые перерисовывается только по чекбоксу. Что тоже можно убрать, например, добавив контекст.
И вот, возвращаемся к тому с чего я начал. Я вот не очень понимаю, зачем было выкладывать такое? Лучше же просто расписать человеческим языком и все. Отвлекаться на такой код и тем более тратить на него место, по моему, контрпродуктивно. Или все таки была цель показать как именно Реакт использовать для таких задач?
Не-е, это я вставил, меня отвлекли и я упустил возможность исправить. Разумеется там не должно быть никакого length.
А мне еще другое любопытно. Описанный пример загрязняет область видимости переменными цикла. Что не очень удобно, если имеются несколько, например, идущих подряд циклов. И что тогда автор делает, придумывает разные имена или использует какой-нибудь такой подход, что бы сохранить оптимизацию производительности:
или
Не знаю. Когда слышу всякое про х10 производительности там, много дешевой колбасы что бы "накормить" десятки тысяч тут, и всякое про нужно для резюме и важность количества над качеством сразу представляется в первую очередь работа по "перекладыванию json-ов".
Да нет, я вопрос поставил именно так, что нужно именно согласие и понимание, что усилия идут на дешевую работу. То, что появился инструмент который может создавать много дешевой дряни вовсе не означает, что это нужно делать.
Это же не так работает. Обычный работник работает за оклад. В редких случаях еще есть премия. Все. Если ваша работа упрощается настолько, что ее может делать ИИ-шка, то такой работник в принципе не нужен. Его можно уволить. Это с одной стороны. А с другой, вот эти вот школы, курсы и т.п., которые сейчас на конвейере создают таких вот специалистов будут так же создавать давление на ЗП.
Но, все это имеет смысл, если все упирается только в количество. Вот вы тоже почему то именно на это акцент сделали.