Ref & List, Keys

Refs

Рефы дают возможность получить доступ к DOM-узлам или React-элементам, созданным в рендер-методе

Когда использовать рефы Ситуации, в которых использования рефов является оправданным:

  • Управление фокусом, выделение текста или воспроизведение медиа.

  • Императивный вызов анимаций.

  • Интеграция со сторонними DOM-библиотеками.

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

  • Например, вместо того чтобы определять методы open() и close() в компоненте Dialog, лучше передавать ему проп isOpen.

Создание рефов Рефы создаются с помощью React.createRef() и прикрепляются к React-элементам через ref атрибут. Обычно рефы присваиваются свойству экземпляра класса в конструкторе, чтобы на них можно было ссылаться из любой части компонента.

Доступ к рефам Когда реф передаётся элементу в методе render, ссылка на данный узел доступна через свойство рефа current.

const node = this.myRef.current;

Значение рефа отличается в зависимости от типа узла:

  • Когда атрибут ref используется с HTML-элементом, свойство current созданного рефа в конструкторе с помощью React.createRef() получает соответствующий DOM-элемент.
  • Когда атрибут ref используется с классовым компонентом, свойство current объекта-рефа получает экземпляр смонтированного компонента.
important

Нельзя использовать ref атрибут с функциональными компонентами, потому что для них не создаётся экземпляров.

React присвоит DOM-элемент свойству current при монтировании компонента и присвоит обратно значение null при размонтировании. Обновление свойства ref происходит перед вызовом методов componentDidMount и componentDidUpdate.

Почитать 📚

List & Keys

Мы можем создать коллекцию элементов и встроить её в JSX с помощью фигурных скобок {}.

К примеру, напишем простой компонент NumberList. Пройдём по массиву numbers, используя функцию JavaScript map(), и вернём элемент <li> в каждой итерации. Получившийся массив элементов сохраним в listItems:

const NumberList = () => {
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);
return <ul>{listItems}</ul>;
};

Когда вы запустите данный код, то увидите предупреждение о том, что у каждого элемента массива должен быть ключ (key).

important

«Ключ» — это специальный строковый атрибут, который нужно указывать при создании списка элементов. Мы обсудим, почему это важно, ниже на странице.

Чтобы исправить проблему с неуказанными ключами, добавим каждому элементу в списке атрибут key.

const NumberList = () => {
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li key={number}>{number}</li>);
return <ul>{listItems}</ul>;
};

Keys

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

note

Лучший способ выбрать ключ — это использовать строку, которая будет явно отличать элемент списка от его соседей. Чаще всего вы будете использовать ID из ваших данных как ключи:

const users = [
{
name: "Alex",
id: 1,
},
{
name: "John",
id: 2,
},
{
name: "Bob",
id: 3,
},
];
const User = (props) => {
return (
<li>
<span>{props.id}</span>--<span>{props.name}</span>
</li>
);
};
class UserList extends React.Component {
render() {
return (
<ul>
{this.props.users.map((user) => (
<li key={user.id}>
<span>{user.id}</span>--<span>{user.name}</span>
</li>
))}
</ul>
);
}
}

Когда у вас нет заданных ID для списка, то в крайнем случае можно использовать индекс элемента как ключ:

const todoItems = todos.map((todo, index) => (
// Делайте так, только если у элементов массива нет заданного ID
<li key={index}>{todo.text}</li>
));

Ключи должны быть уникальными среди соседних элементов

Ключи внутри массива должны быть уникальными только среди своих соседних элементов. Им не нужно быть уникальными глобально. Можно использовать один и тот же ключ в двух разных массивах.

Ключи служат подсказками для React, но они никогда не передаются в ваши компоненты. Если в компоненте нужно то же самое значение, то передайте его явно через проп с другим именем:

const content = posts.map((post) => (
<Post key={post.id} id={post.id} title={post.title} />
));

В примере выше компонент Post может прочитать значение props.id, но не props.key.

Почитать

Практика

  1. UserList

Используя код https://codesandbox.io/s/react-keys-and-refs-64hvo?file=/src/UserList.js

  • Исправить все warning в консоли
  • Добавить кнопку Reset поле поиск должно быть очищено
  • Добавить дополнительную кнопку Add to Top, по клику на которую юзер должен добавляться вверх
  • Добавить дополнительную кнопку Add to Bottom, по клику на которую юзер должен добавляться вниз
  • Добавить кнопку remove для каждого юзера, по клюку на которую юзер должен быть удален и список перерисован с актуальными данными

Select user Добавить возможность по клику на юзера (элемент списка) подсвечивать выбранного юзера (можно добавить className active ),

Выбранный юзер может быть только один

  1. RandomAdvice

    Написать Родительский комопнент для RandomAdvice который должен иметь кнопку Refresh Advice, по клику на которую RandomAdvice component должен быть перерисовна с новым advice

Код RandomAdvice должен быть не тронут

КОД

ДЗ 🏡

GithubUsers

github users

Использую API github https://api.github.com/users Написать комопнент который будет запрашивать юзеров с гитхаб и выводить их списком.

  • Показывать Loading пока данные загружаються с сервера
  • Показывать сообщение об ошибке если запрос с сервера вернул ошибку

Searching advice Использую API https://api.adviceslip.com/ Написать компонент для поиск advice

  • показывать loading пока данные загружаються с сервера
  • показывать сообщение об ошибке если запрос с сервера вернул ошибку
  • показывать No found если запрос с сервера вернул пустой результат
  • добавить кнопку clear рядом с input по клику на которую поле поиска должно быть сброшено

Добавить функцию debounce если поиск срабатывает непосредственно после измененения значения в input Если поиск работает по клику на кнопку search, debounce не нужен

Edit this page on GitHub