Free React For Beginners
3.45K subscribers
231 photos
5 videos
1 file
386 links
💻 Про #React та #frontend та #веб розробку
🧑‍🎓 Для початківців і не тільки

👉 https://www.youtube.com/@reactdev
Download Telegram
N*M (1/3), або дайте мені 1000 ноутбуків

Сьогодні трохи поговоримо про оптимізацію та складність алгоритму на прикладі магазину з ноутбуками.

Уявіть собі що вам прилетіла задача відобразити таблицю з ноутбуками, а бекенд вам повертає два окремі масиви - список ноутбуків та список історій цін, спрощені моделі яких виглядають ось так:

type NoteBook = {id: number};
type PriceHistory = {entityId: number};


Завдання дуже просте: відобразити ноутбуки разом з історією цін.

Ми можемо зробити це в лоб:

function getNotebooksWithPrice(
notes: NoteBook[],
prices: PriceHistory[]
) {
return notes.map((notebook) => ({
...notebook,
price: prices
.filter((x) => x.entityId === notebook.id),
}));
}


Виглядає непогано і читається досить легко. Але тут схована одна проблемка, навіть не проблема, а міна сповільненої дії.

Для того, що зібрати усі ноутбуки з цінами нам потрібно зробити наступні кроки:

1. Пройтися по всьому списку ноутбуків (зробити N операцій де N довжина масиву ноутбуків)
2. Для кожного елементу масиву пройтися по всьому списку цін (зробити M операцій для кожного з ноутбуків, де M довжина масиву цін)

Тобто, для виконання цієї красивої функції нам потрібно N*M операцій. (вітаю, ви тільки що оцінили складність алгоритму 😊, яка склала O(N*M))

З практичної точки зору це означає наступне:

Уявімо собі, що наших ноутбуків 100 штук, а історій цін хоча б втричі більше, тобто 300. Отже, нам потрібно для кожного ноутбуку (100 разів) пройтися по всій історії цін (300 разів) що в сумі дає 30_000 операцій, що може й не так і багато, але вже й не дуже мало. А, якщо ще врахувати, що #React, за своєю природою, дуже часто рендерить компоненти заново, то невдало розмістивши цей код ви будете його виконувати постійно, що, звісно ж буде впливати як на швидкодію вашого застосунку, так і на батареї телефонів наших користувачів.

Але не це наша найбільша проблема. Найбільша наша проблема полягає в тому,що ці списки мають тенденцію до зростання, а кількість їх елементів нічим не обмежена!

Сьогодні у вас в магазині 20 ноутбуків, завтра 120, після завтра 1200 (разом з тими що виведені з асортименту). І функція, яка чудово справлялася зі 120 ноутами, на 1200 почне суттєво "тормозити" ваш UI. А на 2000, коли операцій стане 2_000 * 6_000 = 12 _000_000 на кожен рендер, наша сторінка просто стане колом 😢

Як цьому запобігти?

@reactbeginners
👍17🤯6🔥32
А ну давайте маленький тестик

Як ви знаєте, в #React функціональні компоненти рендеряться заново, в тому числі, коли рендериться їх батьківський компонент (якщо не використовувати React.memo)

Тепер власне тест:

Маємо звичайний, майже класичний React counter:

function Counter({ children }) {
const [c, setCounter] = useState(0);
const increment = () => setCounter(c + 1);
return (
<button onClick={increment}>
{children} {c}
</button>
);
}


Єдиний нюанс з ним - він приймає в пропс children, який відмальовує всередині. В середину ми передаємо отакий примітивний компонент:

function ClickMeText() {
console.log('ClickMeText rendered');
return <>Clicked: </>;
}


Цей компонент - просто текст, який також містить консоль лог, щоб ми бачили коли він рендериться. В цілому виглядає це так:

const App = () => <Counter>
<ClickMeText />
</Counter>


Тепер питання: Я запустив сторінку та ТРИЧІ клікнув на каунтер. Скільки ClickMeText rendered я побачу в консолі, за умови що strict mode вимкнено?

1 раз - ставимо ❤️
3 рази - 👍
4 рази - 🔥

З вас смайлики, з мене пояснення)
🔥8750👍13🤔1🍾1
Друзі, запускаю в пілотному режимі (два тижні) календлі

Якщо вам потрібна порада з #React, або #FrontEnd, або розробкою в цілому - букайте таймслот (понеділок, четвер з 9 по 10 годину)

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

Як проведемо, буду бачити що далі.
❤‍🔥20👍133
Я вивчив #React і що далі?

React це лише бібліотека для відображення, його одного для повноцінної роботи не достатньо.

Вам також знадобляться:

1. UI бібліотека, щоб зекономити на розробці власних компонентів та вберегтися від багів. Ви не хочете писати модалку або data grid самому. Популярні UI бібліотеки MUI (3.7M*), AntDesign (1.3M), ReactBootstrap (1.6М)

2. Стейт менеджер, щоб спростити роботу з даними. Найпопулярніший Redux Toolkit (3.3M), ще можете подивитися MobX(1.3M), або Zustand (3М).

3. Бібліотека для роботи з формами. Якщо у вас на проекті багато форм, раджу розглянути react-hook-form (4.7М) як інструмент що спрощує роботу зі станом форм (touched, dirty, error) та валідацією. Formik, нажаль, більше не підтримується командою (перевірив).

4. Інструменти валідації, які допоможуть спростити валідацію форм та даних що літають між сервером та клієнтом - Yup (5.6М), Joi (9.2M).

5. Якщо у вас багато роботи з часом - розгляньте Luxon (7.4M) або DateFNS (18.5M). Робота з часом буває дуже не тривіальною, тому не створюйте собі баги на пустому місці, беріть ліби.

6. Переклади та інтернаціоналізація - дивимося react-i18next (3.2M) або react-intl(1.4M). Спробуйте відмалювати текст: "У мене N користувачів", де N довільне число, а фраза для перекладу має бути лише одна.

7. Транспорт. Раніше Node.JS не підтримував fetch, та й сам fetch був більш обмежений (наприклад не підтримував відміну запиту), тому зараз на проектах є спеціалізовані бібліотеки для комунікації з сервером. Подивіться axios (47M), він мега популярний.

Але не кидайтесь на цей список одразу. Спокійненько йдіть по пунктам, пробуйте на якомусь пет проекті. Всі ці ліби живі, всі використовуються в комерційних проектах і стануть вам у нагоді.

Ну і ще одне - ліб звичайно більше (той самий React Query) просто все не влізло в список. Але якщо що - пишіть в коментарях, я доповню.

* В дужках - завантажень на тиждень, 7М = 7 мільйонів завантажень на тиждень

Бережіть себе, допомагайте ЗСУ
@reactbeginners
🔥7013👍11❤‍🔥2
Явно погані практики в #React, або що НЕ варто робити без особливих причин

1. Збереження даних в стейті, які можна вирахувати. Якщо дані можна порахувати під час рендеру, просто зробіть це, не треба їх десь зберігати.

2. Використання useEffect для даних, які можна вирахувати. Вам не потрібен useEffect для того щоб порахувати дані - це можна зробити прямо в рендері.

3. Відсутність відписок в useEffect від асинхроних запитів, timeout-ів, подій через .addEventListener. Просто гарна практика яка може врятувати вас від memory leaks, особливо з interval та подіями.

4. Використання useCallback та useMemo без попередніх вимірювань. Використання useCallback та useMemo ускладнює читання вашого коду  - ви зобов'язані пересвідчитись що воно того варте.

5. Збереження локальних даних в глобальному стейті. Всі локальні дані, що потрібні одному компоненту повинні лежати лише локально - не захаращуйте глобальний стейт зайвим, вам з ним ще далі жити.

6. Використання випадкових ключів в списках, або не використання ключів взагалі. Зміна ключа призводить до видалення компоненту з DOM дерева і створення його заново. Це дорого, користуйтеся ключами правильно.

7. Оголошення структур які не залежать від компоненту в самому компоненті (функції, словники, тощо) . Якщо ви можете викинути щось з компоненту просто перемістивши його - зробіть це. Код стане простіше читати і він стане навіть трохи швидше.

8. Використання context-у для швидкозмінних даних (mousemove, scroll, etc). Зміна контексту змушує перерендерюватися усі компоненти що його використовують, а ці події спрацьовують сотнями. Воно вам треба?

Якщо якийсь пункт треба розкрити детальніше - пишіть під постом.

Плейліст присвячений цій темі

Бережіть себе, допомагайте ЗСУ


@reactbeginners
👍72🔥6
Навіщо потрібен React.Context і як не відстрелити собі ногу

Контекст в #React це засіб передачі даних та сутностей всередині застосунку.

Найкраще він підходить для двох речей:

Зберігання даних що потрібні всьому застосунку і які майже ніколи не змінюються, а їх зміна має призводити до перемалювання більшої частини застосунку, наприклад:

1. Дані користувача та стан аутентифікації
2. Локаль та часовий пояс
3. Налаштування теми, якщо ви використовуєте CSSinJS

Передачі сервісів, які потрібні всьому застосунку:

1. Ваша обгортка над fetch або налаштований екземпляр axios
2. Обгортка над LocalStorage, SessionStorage, IndexedDb
3. Обгортка над Navigator

Використання цих сервісів через контекст (а не напряму) дасть вам можливість легко протестувати код який їх використовує. Для цього достатньо лише передати фейкову реалізацію сервісу через провайдер і код готовий до тестування. Поставте 🤝 якщо потрібен окремий приклад такого підходу (викладу на gist)

Чому не використовувати контекст у якості стейт менеджера? Відповідь дуже проста - швидкодія. Коли змінюється значення контексту, всі хто використовує useContext з цим контекстом будуть перемальовані автоматично. Оскільки контексти зазвичай знаходяться "згори", а більшість наших компонентів функціональні, це призводить до перемалювання майже всього застосунку що може дуже не очікувано вилізти боком під час подальшого розвитку застосунку.

А якщо у вас є дані які потрібні по всьому застосунку і які часто змінюються - використовуйте стейт менеджер, наприклад RTK або MobX. Вони спроектовані саме для цього.

Хто дочитав - тримайте маленький лайфак:

Якщо ваші дані ніколи не змінюються - використання Context.Provider взагалі не обов'язкове. React буде використовувати ті дані що ви передали під час створення контексту 😎. А разом з кастомною обгорткою над useContext створення та використання сервісів стає дуже простим.

Корисно? Тоді закиньте 20 гривень на збір на "електрохарчування" для підрозділу 112 бригади ТРО - це дуже важливо, хлопці вирушають на 0. Ще й шанс виграти гарну і корисну книжку або гільзу від ППО.

Дякую пану Дмитру за ідею для допису,

Бережіть себе, допомагайте ЗСУ
,
@reactbeginners
🤝5113👍9
Free React For Beginners
Навіщо потрібен React.Context і як не відстрелити собі ногу Контекст в #React це засіб передачі даних та сутностей всередині застосунку. Найкраще він підходить для двох речей: Зберігання даних що потрібні всьому застосунку і які майже ніколи не змінюються…
Як #React контекст допомагає в тестуванні

Найкращий спосіб пояснити - показати на прикладі. Відкрийте цей гіст і давайте його розберемо

1. Створюємо об'єкт API який буде відповідати за комунікацію із зовнішнім світом і кладемо цей об'єкт в контекст за допомогою createContext
2. В довільному компоненті витягуємо об'єкт API з контексту і використовуємо його.

Поки все зрозуміло, правда? Та "магія" починається далі.

3. В нашому тесті, ми створюємо новий об'єкт API який буде більш підходящий для тестування - він не ходить в мережу, а просто повертає проміс з гарантованим результатом. Далі, ми огортаємо компонент який бажаємо протестувати в ApiContext.Provider, а в value - підсовуємо йому нашу фейкову реалізацію.

Коли React рендерить наш тестовий компонент, він знаходить наш провайдер і замість справжньої реалізації бере нашу нову, фейкову яку і використовує. Так ми можемо протестувати будь-які дані та симулювати будь-які помилки. Спробуйте, наприклад, замість Promise.resolve передати Promise.reject і побачите що станеться з цим компонентом якщо, наприклад не буде інтернету)

Питаннячка?)

П.М. Доречі, код робочий можете спробувати, треба тільки vitest доналаштувати для тестів

Бережіть себе, допомагайте ЗСУ,
@reactbeginners
9🔥3
ЗБІР ЗАКРИТО! ЗВІТ ТА РОЗІГРАШ НА НАСТУПНОМУ ТИЖНІ!

Збір завмер майже на самому фініші - залишилося зібрати 7_910 гривень і я знову буду мучати вас матеріалами про
#React

А щоб все було чесно - мої 3000 гривень теж пішли на збір. Долучайтеся, поширюйте, залишилося ще трохи!


1. І трохи статистики - найбільша пожертва 10_000 гривень
2. Кількість людей що вже прийняли участь - більше 110 осіб
3. Кількість організацій що прийняли участь - 1, дякую Fwdays
4. Найкращий коментар - "Не багато, але від щирого серця!"

Кожні 50грн - шанс виграти розфарбовану гільзу від ППО, якими Київ відбивав шахедів

Всім дякую, давайте сьогодні дотиснемо аби на цьому тижні все передати
👍104🎉2
Як писати чистіший код на #React

1. Робіть маленькі компоненти. Не треба складати все в купу, навіть якщо зараз це виглядає зручно - підтримувати потім буде дуже важко.

2. Розділяйте компоненти на ті що отримують дані та ті що їх відображають. Такий підхід спрощує підтримку та тестування.

3. Пишіть мінімум коду в JSX - виносьте його в блок до return. Так у вас буде блок логіки (до return, та блок відображення - те що в return)

4. Виносьте логіку в окремі функції або кастомні хуки. Компоненти потрібні для відображення, бізнес логіка має лежати окремо і бути протестована.

5. Взагалі виносьте з функцій будь-який код, що не залежить від компоненту. Оці всі магічні числа, масиви для дропдаунів - все це геть, чим менше в компоненті коду що його не стосується тим легше його читати та підтримувати.

6. Мінімізуйте useEffect. Використовуйте useEffect лише якщо немає іншого виходу - наприклад для асинхронних запитів. Намагайтеся його уникати.

7. Зберігайте локальний стейт локально. Якщо дані компоненту потрібні лише цьому компоненту - не варто додавати їх в глобальний стор.

8. Гарно спіть та повільно думайте. Вам платять за вирішення бізнес задачі, а не за кількість символів. Ясний розум - одна з основ чистого коду.

Якщо у вас є бажання та готовність пройти CodeReview в прямому ефірі - пишіть в ПМ.

Бережіть себе, допомагайте ЗСУ,

@reactbeginners
76👍15👏2