Как они работают и почему важны

Существует разрыв между основами JavaScript и тем, что вам нужно для понимания кодирования в React. Заметьте, не огромный, но достаточный, чтобы его стоило изучить. Итак, вот 7 навыков JavaScript, которые вам понадобятся для кодирования в React.

Мы рассмотрим, как они отображаются в React и чем они могут быть вам полезны. Для неизменяемости, условного рендеринга, отображения списков компонентов и многого другого.

И даже если вы не интересуетесь React, вам все равно нужны эти концепции для написания хорошего кода JavaScript.

Но сначала…

1. Истина и ложь

Быстрый, но фундаментальный момент. JavaScript считает некоторые значения «ложными». Хотя они и не являются false, они все же не соответствуют инструкции if. Другими словами, JavaScript ведет себя так, как будто эти значения ложны.

Ложные значения в JavaScript включают (среди прочего):

  • неопределенный
  • нулевой
  • пустая строка
  • пустой массив
  • 0
  • NaN (или не число)

Это полезно для понимания логических операторов и тернарного оператора…

2. Булевы операторы

Вы, несомненно, знакомы с использованием логических операторов && и || в условиях. JavaScript позволяет вам делать гораздо больше. Видите ли, эти операторы не всегда возвращают логическое значение.

Позволь мне объяснить.

Начнем с логического или оператора (||). Это оценивает первый элемент выражения и проверяет, является ли он «ложным» или нет. Если значение «истинно», оператор возвращает первый член, тот, что слева от оператора. Если нет, он возвращает второй.

Представьте, что у нас есть переменная (например, name). Мы не знаем, установлен он или нет. Если он не установлен, мы хотим установить значение по умолчанию. Оператор or позволяет нам сделать следующее:

let defaultedName = name || "defaultName";

Если name равно undefined или null или пустой строке, оператор вернет второй термин: "defaultName". Если name определен, он будет возвращен оператором. Это позволяет нам установить значение по умолчанию.

Логический оператор && имеет прямо противоположное поведение. Если первый термин «правдив», оператор && возвращает второй термин. Давайте посмотрим, как мы можем использовать это в React. Представьте, что у нас есть переменная с именем errorMessage. Он может содержать или не содержать сообщение об ошибке.

В части JSX нашего кода в React мы можем написать что-то вроде этого:

{errorMessage && <span>{errorMessage}</span>}

В этом случае оператор && возвращает диапазон только в том случае, если переменная errorMessage верна. Мы показываем диапазон, только если есть ошибка.

3. Тернарный оператор

Существует сжатый оператор if/else, называемый тернарным оператором. Это работает так, со знаком вопроса и двоеточием:

variableTruthy ? itIsTrue : itIsFalse

Что делает оператор, так это проверяет, является ли переменная «правдивой». Если это так, оператор возвращает первый член после вопросительного знака. Если это не так, возвращается термин после двоеточия. В нашем примере с ошибкой, если мы также хотим показать сообщение, когда ошибки нет, мы можем добавить следующее в наш код JSX:

{ error ? <span>{error}</span> : <span>"There is no error"</span>}

Конечно, в этом конкретном случае мы могли бы написать это проще в пределах диапазона:

<span>{error ? error : "There is no error"}</span>

… но только потому, что я не удосужился добавить какие-либо стили к span для ошибки.

4. Деструктуризация массивов и объектов

Давайте посмотрим на простой хук useState.

const [counter, setCounter] = useState(0);

Посмотрите, как определены переменные counter и setCounter. Они определяются внутри массива. На самом деле происходит то, что мы сопоставляем переменные с возвратом useState. Хук возвращает массив. Этот синтаксис присваивает первое значение массива первой переменной, а второе — второй.

Это более короткий (и более элегантный) способ написания:

const temp = useState(0);
const counter = temp[0];
const setCounter = temp[1];

Как видите, синтаксис реструктуризации намного лаконичнее и не требует временной переменной. Синтаксис для объектов аналогичен. Обычно это сначала появляется в операторах импорта. Например:

import { useState } from 'react';

Как это работает? Допустим, у нас есть пользовательский объект с возрастом и именем:

const user = {
  name: "Bob", 
  age: 42
}

Мы можем получить имя напрямую, используя деструктурирование:

const {name} = user;

Это составило бы

const name = user.name;

5. Функция стрелки

Стрелочная функция — это более лаконичный способ записи функций. А в React лаконичность помогает писать читаемый код. Стрелочные функции также являются естественным способом написания обработчиков useEffect.

Вкратце: «обычный» способ написания функции — использовать ключевое слово function. например.:

function add(a,b) {
  return a + b;
}

Мы можем записать это как стрелочную функцию, объявив:

const add = (a,b) => {
  return a + b;
}

На самом деле, поскольку в этой функции есть только оператор return, мы можем избавиться от скобок и самого оператора return:

const add = (a,b) => a + b

Это особенно полезно при использовании функций массива.

6. Функции массива, в частности карта и фильтр

У массивов есть интересные функции, которые могут с ними работать. В частности, есть два, которые я считаю особенно полезными в React: map и filter.

Оба они принимают функцию в качестве параметра и возвращают новый массив.

Фильтр возвращает массив, содержащий только элементы, для которых функция, переданная в качестве параметра, возвращает истинное значение.

Если мы отфильтруем массив чисел с помощью функции, возвращающей по модулю 2, наш новый массив теперь будет содержать только нечетные числа. Это связано с тем, что четные числа возвращают 0 при выполнении по модулю, а 0 является ложным:

const odd = [1, 2, 4, 7, 9, 22].filter((a) => a % 2);
// odd now only has odd numbers :  [1, 7, 9]

Карта, с другой стороны, возвращает массив, где каждый новый элемент является возвращаемым значением функции. Если мы передаем функцию, которая умножает свой ввод на 2, вывод представляет собой массив двойных значений ввода.

const double = [1, 2, 4, 7, 9, 22].map((a) => a * 2);
// double now has doubles:  [2, 4, 8, 14, 18, 44]

Чем это полезно в React? Скажем, мы создаем приложение списка дел. У нас есть массив задач, которые мы хотим отобразить, хранящийся в переменной tasks. Каждый элемент имеет (например):

  • an ID,
  • Заголовок,
  • завершенное состояние, которое может быть истинным или ложным.

Допустим также, что мы определили компонент Task. Мы можем создать список, используя функцию карты, чтобы вернуть компонент задачи для каждого элемента:

{ tasks.map((task) => <Task key={task.id} task={task} /> }

Мы можем отобразить только незавершенные элементы, используя filter, чтобы скрыть элементы, для которых значение Complete равно true:

{ 
tasks.filter(task => !item.complete).map((task) => <Task key={task.id} task={task} /> 
}

(Небольшое замечание: нам нужно указать значение key, чтобы помочь React точно отслеживать, что изменилось.)

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

7. Оператор спреда (и сокращение свойства объекта)

Если вы используете объекты в своем состоянии, вам нужно начать использовать оператор распространения. Оператор распространения позволяет нам создать дубликат объекта со всеми теми же значениями.

const user = {
  name: "Bob", 
  age: 42
}

const user1 = user;
const user2 = {...user};

console.log(user == user1); // true 
console.log(user == user2); // false

Почему это полезно? React отслеживает изменения, чтобы знать, когда нужно повторно отображать части дерева компонентов. В приведенном выше примере user и user1 — это один и тот же объект.

Если мы, например, установим свойство age равным 43 для user1, user1 все равно будет равно user.

Теперь представьте, что React отслеживает состояние объекта user. Изменение значения одного из свойств пользовательского объекта не приведет к обнаружению изменения состояния. Скажем, у нас есть функция setUser, предназначенная для обновления состояния пользователя. Если мы делаем:

user.age = 43;
setUser(user);

Это не приведет к обнаружению изменений. Объект user остается тем же самым объектом. Нам нужно создать новый объект, используя оператор распространения, и так:

setUser({...user, age: 43});

Что здесь происходит?

Две фигурные скобки означают, что мы создали новый объект. Оператор распространения действует так, как будто он разделяет (или расширяет) исходный объект.

Если бы мы явно написали, что здесь происходит… Это было бы особенно многословно. Нам нужно сначала создать пустой новый объект. Затем мы перечисляем все ключи на объекте user. Затем мы перебираем список ключей. При этом мы устанавливаем значение свойства в новом объекте на соответствующее значение в старом объекте. Наконец, мы устанавливаем новое измененное значение.

const newUser = {}
let keys = Object.keys(user); 

for(let i = 0; i < keys.length; i++) {
	let key = keys[i];
	newUser[key] = user[key];
}

newUser.age = 43;

Это вряд ли лаконично.

Оператор спреда объединяет все это в одну строку. И получившийся код будет таким же (если не более) читаемым, как только вы поймете, что он означает.

Делаем следующий шаг (ы)

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

Что еще нужно освоить, чтобы продолжать учиться?

Во-первых, очень важно понять, как работают Promises и async/await. Это не основная часть React. Есть крючки, которые скрывают сложность для вас. Но если вы хотите освоить JavaScript, это неизбежно.

Если вы хотите освоить React, вам нужно понять, как работают хуки, и как избежать ошибок новичка.

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord . Заинтересованы в хакинге роста? Ознакомьтесь с разделом Схема.