UZ0 название идейной группы которая любит игры, общение и хочет делиться знаниями
Описаное ниже носит рекомендательный характер
- Отступы используем в 2 пробела, без табуляции.
- Точку с запятой всегда ставим.
- Между аргументами у функций - пробел. Между скобками и объявлением - пробел, за исключением объявления анонимной функции
function(matchId, tournamentId) {}
for (let i = 0; i < length; i++) {}
if (error) {}
- Фигурные скобки ставятся через пробел
function() {
...
}
- В конструкции
if
даже если используется одна строка - делаем перенос и добавляем фигурные скобки.
Плохо
if (error) this.doSomething()
Хорошо
if (error) {
this.doSomething();
}
- Переменные декларируются каждая с новой строки
const sum = 0;
const multiple = 1;
const - для неизменяемых переменных, let для изменяемых, var не используем.
- Кавычки в javascript ставим одинарные, в разметке и в стилях - двойные.
- В перечислениях последнюю запятую ставим.
const Component = ({
name,
type,
className,
}) => {};
- Блоки с вложенностями выделяются пробелом
const sum = 0;
for() {
...
}
const multiple = 1;
Перед комментарием ставим перенос строки
const sum = 0;
// комментарий
const anotherVar = 1;
Переменные именуются в camelCase. Никаких нижних подчеркиваний.
const variableWithData = 0;
Если переменная будет хранить булевое значение, ее имя должно быть соответствующим
const isModalShown = false;
const isDataExist = true;
Булевые пропсы в react называем, добавляя no / with
<Component
noHeader
withCaptions
/>
Функции именуются также в camelCase и должны называться исходя из своих назначений.
- Если функция должна вернуть какие-то данные, называем
getSomething
. - Если функция должна проверить что-то, называем
isSomething
. - Если функция должна сделать что-то, называем
глаголНадЧемВыполнитьДействие
.
function getTournament() {}
function getUserProfile() {}
function isEqual() {}
function isDataExist() {}
function loadTournament() {}
function openAddTournamentModal() {}
Объекты/классы/компоненты должны называться в camelCase, но с большой буквы
new GameStage();
class Button {}
Все папки и файлы именуются через дефис.
/components
../button
../add-modal
../new-tournament
Почти всегда в коде можно избежать использования else. Стараемся так и делать.
Такой код:
if (isEqual) {
...
} else {
...
}
Можно заменить на такой:
if (!isEqual) {
... // тут вы делаете все, что хотели сделать в else
return;
}
... // тут то, что хотели делать в if
Избегаем больших вложенностей. По-хорошему, их не должно быть больше 2-х.
Это плохо:
if (tournament) {
if (tournament.matches) {
tournament.matches.forEach(match => {
...
});
}
}
Этот код можно переделать примерно так:
if (!tournament) {
return;
}
if (!tournament.matches) {
return;
}
tournament.matches.forEach(match => {
...
});
Не делаем больших методов. Если метод больше 50-ти строк, то уже стоит задуматься о его разбиении на более мелкие.
Не передаем функциям больше 2-х параметров. Если уж этого не избежать, передавайте объект и там указывайте все данные, что хотели передать.
Также нужно избегать передачи булевых параметров. Так не надо:
someFunc(param1, param2, param3, param4, param5);
Если такого не избежать, делаем так:
someFunc({
param1,
param2,
param3,
param4,
param5,
});
Не нужно оставлять комментарии что будет происходить в функции и т.д. Оставляем комментарии только если хотим объяснить почему тут именно такой код. Что происходит должно быть понятно еще исходя из названия функции или переменной.
Так не надо:
// эта переменная для хранения суммы очков пользователей
const qwe = 0;
users.forEach(user => {
// тут мы не считаем свои очки
if (user.id === this.currentUser.id) {
return;
}
// тут мы складываем очки
qwe += user.balance;
});
Так надо:
const pointsSum = 0;
users.forEach(user => {
// не учитываем свои очки, ПОТОМУ ЧТО...
if (user.id === this.currentUser.id) {
return;
}
pointsSum += user.balance;
});
Чтобы было проще ориентироваться во всех компонентах проекта, создаем свой порядок методов
class
constructor
state
методы компонента
lifecicle-методы
render-методы
render()
Внутри render()
тоже должен быть порядок, поэтому
render() {
return <div>
<div>
...
</div>
<Modal />
<Modal />
<Notification />
<Preloader />
</div>;
}
всякий мусор типа модалок/нотификейшенов выносим в самый низ, чтобы не мешались. А еще лучше вынести их в отдельный контейнер в корень. Как это сделать можно прочитать ТУТ
Важно поддерживать в чистоте разметку, поэтому удаляем из DOM все, что не используется в данный момент:
state = {
isLoading: false,
};
render() {
return <div>
{this.state.isLoading &&
<Preloader />
}
</div>;
};
Всякие уязвимые места выносим из jsx в начала метода render()
.
Например это:
render() {
return <div>
<span>{moment(tournament.date).format('MM DD')}</span>
</div>;
}
Должно быть переписано так:
render() {
const date = moment(tournament.date).format('MM DD');
return <div>
<span>{date}</span>
</div>;
}
Если в jsx используется несколько проверок, также выносим в переменную выше:
render() {
return <div>
{items && items.length > 0 && this.state.isLoaded &&
<p>...</p>
}
</div>;
}
Переписываем так:
render() {
const isBlockShown = items && items.length > 0 && this.state.isLoaded;
return <div>
{isBlockShown &&
<p>...</p>
}
</div>;
}
Обратите внимание как оформляется проверка
{rule &&
<Component />
}
Надо избегать такой записи функций в jsx:
<button onClick={() => this.method()} />
Если вы не передаете в метод какой-то параметр (типа id), то это можно переписать так:
<button onClick={this.method} />
Также в стрелочных функциях, если они написаны в одну строку как в примере выше, не нужно ставить фигурные скобки. И если у вас передается один параметр, круглые скобки тоже не нужны.
В стрелочных функциях, если вы ее записываете в одну строку, то, код, который вы напишите после =>
функция будет возвращать. То есть это:
map(items, item => item.id);
Будет эквивалентно этому:
map(items, function(item) {
return item.id;
});
А если нужно, чтобы функция вернула объект, вокруг фигурных скобок добавляются круглые:
connect(
state => ({
users: state.users,
}),
)
Предыдущая запись эквивалентна этой:
connect(
function(state) {
return {
users: state.users,
};
}
)
В разметке также как в js отделяем переносом вложенные блоки:
<p>...<p>
<div>
<p>...</p>
</div>
<div></div>
У нас не используется nesting, поэтому все стили описываются один за другим. Между каждым блоком стилей ставится перенос строки.
.class1 {
...
}
.class2 {
...
}
Для каждого класса прописываем всю цепочку классов. То есть делаем не так:
.container {}
.list {}
.item {}
а так:
.container {}
.container .list {}
.container .list .item {}
У всех div-ов, которые добавлены должен быть класс.
Не должно быть записей типа:
.form > div input {}
Верстку нужно делать так, чтобы для полного изменения темы понадобилось всего лишь изменить цвета нескольких переменных. Поэтому все цвета должны быть занесены в css-переменные.
Переменные для цветов называем по назначению этого цвета, а не по самому его цвету. То есть переменные не должны называться как-нибудь так:
--red-color: #f00;
--white-color: #fff;
Поэтому выделяем среди цветов основные и соответствующе называем. В основном у проектов есть такие цвета:
- основной цвет;
- акцентирующий цвет;
- цвет фона;
- цвет текста.
И еще разные дополнительные. Поэтому цвета называем как-то так:
--primary-color
--accent-color
--main-background-color
--text-color
--error-color
и тд.
Также используем переменные если:
- ее можно переиспользовать в нескольких местах;
- нужно вычислить какое-то сложное значение и чтобы не засорять формулами сами свойства в блоке стиля;
- мы делаем компонент, и по проекту используются разные значения какого-то css-свойства компонента, и его постоянно нужно переопределять. Переопределяем переменную, а не само свойство. Также для этих дел можно добавлять дефолтные значения var(--variable, 100px) - назначаем --variable из другого места и свойство меняется без никаких конфликтов.
В верстке важно предусматривать все случаи, когда в тексте оказывается больше символов, чем предполагалось. Поэтому всем тэгам, которые должны быть в одну строку нужно прописывать обрезание строки.
Разберем на примере одного часто встречающемся блока.
Если в строке вдруг оказалось слишком много символов, страница начинает выглядеть не очень
На этом примере две проблемы. Во-первых поехал текст, а во-вторых кнопка справа сжалась, а такого быть не должно. Как решается:
Учитываем, что родительский div имеет display: flex
.
.title {
flex-grow: 1;
overflow: hidden;
min-width: 0;
white-space: nowrap;
text-overflow: ellipsis;
...
}
.button {
flex-shrink: 0;
}
flex-grow: 1
растягивает дочерний элемент на всю ширину, которую он может занять. Так мы двигаем кнопку в правую часть.
min-width: 0
нужен, т.к. часто появляется баг, при котором текст не обрезается и растягивается за пределы контейнера.
Также иногда для фикса min-width: 0
нужно прописать родителю.
flex-shrink: 0
у кнопки решает как раз вторую проблему - кнопка перестает сжиматься при растяжении заголовка.
Также нужно не забывать добавлять отступы между обрезаемой строкой и соседними элементами для большей читаемости. Добавляем margin-left
кнопке.
Теперь при перезаполнении блок выглядит не так уж плохо.
Разберем еще пример, который нужно прорабатывать в верстке - кнопки с прозрачным фоном
Им нужно создавать большую кликабельную область, т.к. например в данном случае будет сложно попасть по кнопке из-за маленького размера.
В этом примере имеем компонент <Button />
, с фиксированной шириной и высотой, прописанной в компоненте кнопки --height: 46px;
и размером иконки --icon-size: 10px;
.
Вот так он будет выглядеть, если он будет с большой кликабельной областью, и если его просто добавить в модалку
В модалке используется единый padding по бокам, поэтому кнопка визуально находится не с краю. Поэтому в таких случаях добавляем кнопке отрицательный margin-right, равный половине разницы ширины кнопки и иконки:
margin-right: calc(((var(--height) - var(--icon-size)) / 2) * -1);
Тем самым мы сохраняем большую кликабельную область для кнопки и выравниваем ее визуально относительно края.