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

Firebase имеет две опции базы данных, каждая из которых имеет потрясающие возможности реального времени. Например, вы можете подписаться на изменения в документе, хранящемся в облачном хранилище firebase, с помощью следующего фрагмента кода JavaScript.

db.collection("cities").doc("SF")
    .onSnapshot(function(doc) {
        console.log("Current data: ", doc.data());
    });

Обратный вызов, предоставленный функции onSnapshot(), срабатывает каждый раз, когда документ изменяется. Локальные записи из вашего приложения немедленно активируют его с помощью функции, называемой компенсацией задержки.

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

Конечным продуктом будет IRC-подобный глобальный чат-приложение, в котором мы сначала просим пользователя ввести псевдоним. Простой.

Строительные леса

Новое приложение для реагирования можно легко создать с помощью официального инструмента cli create-react-app со следующими командами терминала (для хуков реакции требуется react и react-dom v16.7.0-alpha).

npm i -g create-react-app
create-react-app react-firebase-chatroom
cd react-firebase-chatroom
npm i -S [email protected] [email protected]

Настройка firebase также довольно проста. Создайте новый проект из консоли firebase. Настройте базу данных firebase в режиме реального времени в тестовом режиме. Инициализируйте локальный проект командой firebase-tools. Выберите базу данных реального времени и хостинг в качестве включенных функций. Выберите build в качестве общедоступного каталога. Любой другой вариант можно оставить как есть.

npm i -g firebase-tools
firebase-tools init
npm i -S firebase

Возможно, вам потребуется войти в систему, прежде чем вы сможете инициализировать репозиторий.

Структура базы данных будет выглядеть следующим образом.

Создание приложения с использованием старых добрых компонентов на основе классов

Перехватчики React все еще являются экспериментальной функцией, и API может измениться в будущем. Итак, давайте сначала посмотрим, как приложение может быть построено с использованием компонентов на основе классов. Я использовал только компонент App, потому что логика приложения была достаточно простой.

Пользователю будет предложено присоединиться с помощью псевдонима и адреса электронной почты, если переменная joined равна false. Первоначально он установлен в значение false в constructor.

constructor() {
    super();
    this.state = {
      joined: false,
      nickname: "",
      email: "",
      msg: "",
      messages: {},
    };
    this.chatRoom = db.ref().child('chatrooms').child('global');
    this.handleNewMessages = snap => {
      console.log(snap.val());
      if (snap.val()) this.setState({ messages: snap.val() });
    };
  }
  componentDidMount() {
    this.chatRoom.on('value', this.handleNewMessages);
  }
  componentWillUnmount() {
    this.chatRoom.off('value', this.handleNewMessages);
  }

Все сообщения изначально извлекаются из firebase в componentDidMount методе жизненного цикла. Метод on в db ref принимает тип события и обратный вызов в качестве аргументов. Каждый раз, когда пользователь отправляет новое сообщение и обновляет базу данных, функция handleNewMessages получает снимок обновленных данных и обновляет состояние новыми сообщениями. Мы можем отказаться от подписки на обновления базы данных в методе жизненного цикла componentWillUnmount, используя метод off в db ref.

Сообщение можно отправить, добавив сообщение в ссылку чата в базе данных. Метод push ссылки создает уникальный идентификатор для новой записи и добавляет его к существующим данным.

this.chatRoom.push({
  sender: this.state.nickname,
  msg: this.state.msg,
});

Сообщения обрабатываются циклически по объекту messages.

{Object.keys(this.state.messages).map(message => {
  if(this.state.messages[message]["sender"] === this.state.nickname)
    // render the user's messages      
  else
    // render messages from other users
})}

Последний компонент App будет выглядеть так.

Найдите суть здесь.

Миграция на перехватчики реакции

Самый простой крючок - это крючок useState. Он принимает начальное состояние и возвращает переменную состояния и функцию, которая позволяет вам его обновить. Эта функция действует как замена this.setState. Например, логика состояния псевдонима может быть изменена следующим образом.

const [nickname, setNickname] = useState("");
const handleNameChange = e => setNickname(e.target.value);
.
.
.
// during render
<input placeholder="Nickname" value={nickname} onChange={handleNameChange} />

Следующая задача - найти место для логики внутри методов жизненного цикла. Вот здесь-то и появляется ловушка useEffect. Здесь мы выполняем логику, которая имеет побочные эффекты. Его можно рассматривать как комбинацию всех методов жизненного цикла. useEffect также может при желании возвращать функцию, которая используется для очистки (например, для отмены подписки на событие).

useEffect(() => {
  const handleNewMessages = snap => {
    if (snap.val()) setMessages(snap.val());
  }
  chatRoom.on('value', handleNewMessages);
  return () => {
    chatRoom.off('value', handleNewMessages);
  };
});

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

По умолчанию useEffect запускается как после первого рендеринга , так и после каждого обновления.

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

function useEmail(defaultEmail) {
  const [email, setEmail] = useState(defaultEmail);
  const [isValidEmail, setValidEmail] = useState(defaultEmail);
  function validateEmail(email) {
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(String(email).toLowerCase());
  }
function handleEmailChange(e) {
    if (validateEmail(e.target.value)) {
      setValidEmail(true);
    }
    setEmail(e.target.value);
  }
  return {
    email,
    handleEmailChange,
    isValidEmail
  };
}

И в своих компонентах вы можете использовать настраиваемый хук, как показано ниже.

// in your components
const { email, handleEmailChange, isValidEmail } = useEmail("")
.
.
.
<input value={email} value={email} onChange={handleEmailChange} />
// show error message based on isValidEmail

Пользовательские хуки также упрощают модульное тестирование части логики, независимой от компонентов, которые используют ловушку.

Последний App компонент выглядит следующим образом.

Найдите суть здесь.

Есть еще кое-что, что можно прочитать о крючках

  1. Мотивация за крючками
  2. Золотые правила крючков
  3. Справочник по API хуков
  4. Разбираемся с крючками, Дэн Абрамов

Спасибо за чтение и удачного взлома!

Найдите меня в Twitter и GitHub.