суббота, 26 декабря 2020 г.

A programmer: JavaScript #28. Routing in React

Некоторое время назад делал я тестовое задание по стеку MERN (MongoDB, ExpressJS, React, NodeJS). Сделать вовремя не сумел, но добрые люди согласились мне помочь доделать его - для себя, просто чтобы разобраться. Важный комментарий был мне дан по поводу того, что при маршрутизации моя программа перезагружает страницу, чего не должно быть, поскольку в этом случае теряется вся логика Single Page Application, для чего, собственно, и разработан React. Логика, напомню, состоит в том, что вместо загрузки необходимых страниц с сервера по каждому запросу, должно загружаться всё и сразу (кроме баз данных), и в зависимости от запроса - отрисовываться на клиенте то, что нужно, но без перезагрузки страницы. И понял я, что с маршрутизацией в React'e мне, оказывается, ещё нужно разобраться получше.

Итак, для маршрутизации в React'e существует модуль react-router-dom, который предоставляет несколько ключевых инструментов:

BrouserRouter (обычно импортируемый как просто Router) - модуль, в котором, собственно, должна быть описана маршрутизация.

Router - в сущности, аналог href - в нем прописывается путь, в зависимости от которого должно быть отрисовано нужное содержание.

Если кроме непосредственных ссылок надо обработать отсутствующую страницу, то Route'ы надо обернуть в Switch.

Кроме того, можно использовать Redirect, Link и NavLink (который отличается от Link тем, что в нем можно ещё и ссылаться не описание стилей для линков).

Так вот, в моем случае надо было использовать Link вместо Route - в этом случае страница не перезагружается, и маршрутизация осуществляется на клиенте, в противном случае идет запрос на сервер:

<Link to="/"><button type="button">Home</button></Link>

Информация взята отсюда, отсюда и отсюда.

пятница, 18 декабря 2020 г.

A programmer: JavaScript #27. Hooks in React

Поскольку, грубо говоря, в JavaScript всё есть объект, то и компоненты React тоже вполне логично интерпретируются как объекты. А у объектов, как известно, есть состояние (state) и есть поведение. Состояние хранится в самом объекте, и его можно в нем же менять через this.setState. Но в последнее время разработчики React стараются отходить от такой практики и использовать компоненты как "функциональные компоненты", или просто функции. А функции не имеют состояния (stateless). Но состояние - вещь необходимая, и возникшую проблему надо решать - для этого и придумали хуки (hooks). Хук - это функция, которая меняет состояние, которое хранится в локальной переменной.

Классический пример - использование хука useState для счетчика (сначала его надо импортировать и библиотеки 'react'):

const [count, setCount] = useState(0);

Здесь происходит "деструктуризация массива" - объявляются и переменная состояния (count), и собственно хук (setCount). То есть запись эквивалентна следующей:

var countStateVariable = useState(0);

var count = countStateVariable[0]; // Объявление переменной состояния

count = 0; // Присваивание начального значения

var setCount = сountStateVariable[1]; // Объявление хука

Теперь к ним можно обращаться в рендере:

button onClick={() => setCount(count + 1)}

Другой классический пример – хук useEffect. Он определяет действия, которые должны быть выполнены после каждого рендера – то есть заменяет собой встроенные методы, которые связанны с жизненным циклом компонента (componentDidMount, componentDidUpdate и др.). Поскольку перерисовка компонента обычно связана с изменением состояния (за которое обычно отвечает useState), то часто оба эти хука используются вместе:

const [count, setCount] = useState(0);

useEffect(() => { document.title = `Вы нажали ${count} раз` });

В данном случае document.title будет перерисовываться при каждом изменении состояния.

Существуют и другие хуки, а также можно написать собственные.

Информация взята отсюда, отсюда, отсюда.

среда, 16 декабря 2020 г.

A programmer: JavaScript #26. A conditional statement in React

Некоторое время назад мучился с небольшой проблемой: вроде бы программа работала правильно, но в консоли браузера откуда-то выскакивало сообщение "GET http://localhost:3000/undefined". Расследование показало, что это связано с тем, что я добавляю в базу данных объект без картинки, при этом у меня должен отрисовываться элемент, который имеет свойство

backgroundImage: `url(${this.state.picture})`

То есть, когда картинки нет, он выбрасывает undefined, что логично. Мне посоветовали написать так:

this.state.picture && { backgroundImage: `url(${this.state.picture})` }

"Странная запись" - подумал я, имея в виду оператор "И", и пошел разбираться. Оказалось, что всё логично: React читает эту строчку последовательно слева направо. Если картинка в state есть, то он И отрисовывает её, а если её нет, то на операторе "И" прекращает читать строку, потому что вне зависимости от того, что дальше, значение будет false, и до запроса на вывод картинки дело не доходит.

вторник, 15 декабря 2020 г.

A programmer: JavaScript #25. Widdleware in ExpressJS

Тема, которая почему-то вообще не попадалась мне на глаза раньше, но оказалась полезной и достаточно несложной. Напомню, что ExpressJS - это фреймворк для более простой работы с вебсервером. Грубо говоря, если в "ванильном" варианте надо было работать с XMLHttpRequest-объектом (XHR) NodeJS'a, то в ExpressJS создается свой объект app, через каторый и идет взаимодействие с сервером. Так вот, маршрутизация предполагает, что серверная часть имеет эндпойнты (например, "/api"), при обращении к которым выполняются некоторые действия. Например:

app.get("/api", (req, res) => {

    // code

})

Так вот, существует возможность указать некоторые функции, которые должны быть выполнены ПЕРЕД выполнением данного года. Для этого определяется некоторая функция, кроме req и res она принимает параметр next, который вызывается в конце этой функции, чтобы передать выполнение следующему middleware или собственно основному коду (если надо выдать ошибку, она передается как параметр внутри next(error), никакой другой параметр там передаваться не может). Например:

const middleware = (req, res, next) => {

    // code

    next();

}

Чтобы подключить middleware, надо указать:

app.use("/api", middleware);

Если указать без указания на рут, middleware будет "подключено" глобально, то есть будет выполняться в любом руте:

app.use(middleware);

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

Информация взята отсюда, отсюда и отсюда.