Storage

За пределами пары ключ/значение: конкурентное видение

Хотя в истории было много уловок и обходных путей, нынешнее состояние HTML5-хранилища на удивление благополучно. Новый API был стандартизирован и включен во все основные браузеры, платформы и устройства. Для веб-разработчика такое увидишь не каждый день, не так ли? Но это больше, чем «5 мегабайт пар ключ/значение» и будущее постоянного локального хранилища это… как бы сказать… ну, пусть конкурентное видение.

Одно видение является аббревиатурой, которую вы уже знаете — SQL. В 2007 году Google запустил Gears, кроссбраузерный плагин с открытым исходным кодом, в который включена встроенная база данных на основе SQLite. Этот ранний прототип позже повлиял на создание спецификации Web SQL Database. База данных Web SQL (ранее известная как «WebDB») обеспечивает тонкую оболочку вокруг базы данных SQL, что позволяет делать следующие вещи из JavaScript:

openDatabase(‘documents’, ‘1.0’, ‘Local document storage’, 5*1024*1024, function (db) {
  db.changeVersion(», ‘1.0’, function (t) {
    t.executeSql(‘CREATE TABLE docids (id, name)’);
  }, error);
});

Как вы можете видеть, большая часть действий находится в строке с методом ExecuteSQL. Эта строка может поддерживать любые команды SQL, в том числе SELECT, UPDATE, INSERT и DELETE. Это все равно, что серверное программирования баз данных, за исключением того, что вы делаете это с JavaScript! О радость!

Спецификация базы данных Web SQL была реализована в четырех браузерах и платформах.

Поддержка базы данных Web SQL
IE Firefox Safari Chrome Opera iPhone Android
4.0+ 4.0+ 10.5+ 3.0+ 2.0+

Конечно, если вы использовали более чем одну базу данных в своей жизни, то знаете, что «SQL» это скорее маркетинговый термин, чем жесткий и быстрый стандарт (кто-то может сказать то же самое об HTML5, но это не важно). Конечно, есть актуальная спецификация SQL (она называется SQL-92), но в мире нет сервера баз данных, который соответствует только этой спецификации

Есть Oracle SQL, Microsoft SQL, SQL в MySQL, SQL в PostgreSQL, SQL в SQLite. В действительности, каждый из этих продуктов с течением времени добавляет новые функции SQL, так что недостаточно даже произнести «SQL в SQLite». Вы должны сказать «версия SQL, который поставляется вместе с SQLite версии X.Y.Z».

Все это подводит нас к следующей оговорке, в настоящее время размещенной вверху спецификации Web SQL.

Именно на этом фоне я расскажу вам о другом конкурентном видении для продвинутых, постоянное локальное хранилище для веб-приложений: Indexed Database API, ранее известное как «WebSimpleDB», теперь ласково называемое IndexedDB.

Indexed Database API предоставляет то, что называется хранилище объектов, при этом много идей заимствовано из баз данных SQL. Есть «базы данных» с «записями», каждая запись имеет определенное количество «полей». У каждого поля есть определенный тип данных, который определяется при создании базы данных. Вы можете выбрать часть записей, затем перечислить их «курсором». Изменения в хранилище объектов обрабатываются с «транзакциями».

Если вы хоть раз программировали базы данных SQL, то эти термины, вероятно, вам знакомы. Основная разница в том, что хранилище объектов не имеет структурированного языка запросов. Вы не напишите условие вроде «SELECT * from USERS where ACTIVE = ‘Y'». Вместо этого используются методы, предоставляемые хранилищем объектов для открытия базы USERS, перечисления записей, фильтрации наших записей и использование методов доступа для получения значения каждого поля оставшихся записей. An early walk-through of IndexedDB (Ранний проход IndexedDB) это хорошее руководство о том, как работает IndexedDB и сравнение IndexedDB с Web SQL.

На момент написания IndexedDB был реализован только в бета-версии Firefox 4. Для контраста, Mozilla заявила, что никогда не будет воплощать Web SQL. Google заявил, что они рассматривают поддержку IndexedDB для Chromium и Google Chrome. И даже Майкрософт заявил, что IndexedDB «отличное решение для веб».

Что вы как веб-разработчик можете делать с IndexedDB? На данный момент практически ничего, кроме некоторых технологических демонстраций. Через год? Возможно.

Веб-хранилище. Назначение localStorage и sessionStorage

Веб-хранилище — это данные, хранящиеся локально в браузере пользователя. Существует 2 типа веб-хранилищ:

  • LocalStorage;
  • SessionStorage.

В них вы можете хранить информацию в формате ключ-значение. Ключ и значение – это всегда строки.

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

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

  • SessionStorage – выполняет это в течение определённого промежутка времени (сессии). Закрытие вкладки или браузера приводит их к удалению. При этом данные в SessionStorage сохраняются при обновлении страницы.
  • LocalStorage – осуществляет это в течение неограниченного времени. Они сохраняются при перезагрузке браузера и компьютера. Их длительность хранения ничем не ограничена. Но, хоть эти данные могут храниться бесконечно в браузере, обычный пользователь может их очень просто удалить, например выполнив очистку истории (при включенной опции «файлы cookie и другие данные сайтов»).

Хранилище LocalStorage похоже на cookies. Оно также применяется для хранения данных на компьютере пользователя (в браузере). Но кроме общих сходств имеется также и много отличий.

Cookies vs. LocalStorage: В чём разница

Отличия между cookies и LocalStorage:

  • по месту хранения (куки и данные LocalStorage хранятся на компьютере пользователя в браузере);
  • по размеру (cookies ограничены 4 Кбайт, а размер LocalStorage — 5 Мбайт);
  • по включению этих данных в HTTP-заголовок (куки в отличие от данных локального хранилища включаются в состав запроса при отправке его на сервер, а также сервер их может добавлять в ответ при отправке его клиенту; таким образом cookies являются частью HTTP-протокола, и увеличивают объём передаваемых данных от клиента серверу и обратно);
  • по доступности данных (печеньки можно прочитать и установить как на сервере, так и на клиенте; на клиенте доступны все куки, кроме тех, у которых установлен флаг ; LocalStorage доступны только в браузере посредством JavaScript API);
  • по времени хранения данных (куки хранятся ограниченное время (до конца сеанса или истечения указанной даты), нахождение данных в локальном хранилище не ограничено по времени);
  • по удобству использования в JavaScript (работа с LocalStorage в JavaScript организовано намного удобнее чем с cookies);
  • по необходимости информирования пользователей Евросоюза (при использовании cookies сайт в ЕС должен получать на это разрешение от пользователей; для данных локального хранилища это не требуется);
  • по назначению (куки в основном используются для управления сеансом, персонализации и отслеживания действий пользователя, в то время как LocalStorage применяется в качестве обычного локального хранилища информации на компьютере пользователя).

Что использовать: LocalStorage или cookies? На самом деле, ответ на этот вопрос очень прост. Если вам не нужно отправлять данные с каждым HTTP-запросом на сервер, то в этом случае лучше использовать для хранения данных LocalStorage.

Безопасность данных

Хранилище LocalStorage привязана к источнику (домену, протоколу и порту). Данные, находящиеся в некотором источнике, доступны для всех сценариев страниц этого же источника. Из сценария, находящегося в одном источнике, нельзя получить доступ к данным, определяемым другим источником.

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

Итоги

Основные характеристики LocalStorage и SessionStorage:

  • данные хранятся в виде пар «ключ-значение»;
  • хранить можно только строки;
  • если вам необходимо хранить в этих хранилищах массивы и объекты, то сначала вы должны их превратить в строки, например, используя метод . Для преобразования строки обратно в массив или объект, можно использовать . Подробнее об этом позже.

Хранилище объектов

Чтобы сохранить что-то в IndexedDB, нам нужно хранилище объектов.

Хранилище объектов – это основная концепция IndexedDB. В других базах данных это «таблицы» или «коллекции». Здесь хранятся данные. В базе данных может быть множество хранилищ: одно для пользователей, другое для товаров и так далее.

Несмотря на то, что название – «хранилище объектов», примитивы тоже могут там храниться.

Мы можем хранить почти любое значение, в том числе сложные объекты.

IndexedDB использует для клонирования и хранения объекта. Это как , но более мощный, способный хранить гораздо больше типов данных.

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

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

Ключ должен быть одним из следующих типов: number, date, string, binary или array. Это уникальный идентификатор: по ключу мы можем искать/удалять/обновлять значения.

Как мы видим, можно указать ключ при добавлении значения в хранилище, аналогично . Но когда мы храним объекты, IndexedDB позволяет установить свойство объекта в качестве ключа, что гораздо удобнее. Или мы можем автоматически сгенерировать ключи.

Но для начала нужно создать хранилище.

Синтаксис для создания хранилища объектов:

Обратите внимание, что операция является синхронной, использование не требуется

  • – это название хранилища, например для книг,
  • – это необязательный объект с одним или двумя свойствами:

    • – путь к свойству объекта, которое IndexedDB будет использовать в качестве ключа, например .
    • – если , то ключ будет формироваться автоматически для новых объектов, как постоянно увеличивающееся число.

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

Например, это хранилище объектов использует свойство как ключ:

Хранилище объектов можно создавать/изменять только при обновлении версии базы данных в обработчике .

Это техническое ограничение. Вне обработчика мы сможем добавлять/удалять/обновлять данные, но хранилища объектов могут быть созданы/удалены/изменены только во время обновления версии базы данных.

Для обновления версии базы есть два основных подхода:

  1. Мы можем реализовать функции обновления по версиям: с 1 на 2, с 2 на 3 и т.д. Потом в сравнить версии (например, была 2, сейчас 4) и запустить операции обновления для каждой промежуточной версии (2 на 3, затем 3 на 4).
  2. Или мы можем взять список существующих хранилищ объектов, используя . Этот объект является , в нём есть метод , используя который можно проверить существование хранилища. Посмотреть, какие хранилища есть и создать те, которых нет.

Для простых баз данных второй подход может быть проще и предпочтительнее.

Вот демонстрация второго способа:

Чтобы удалить хранилище объектов:

How does localStorage work?

To use in your web applications, there are five methods to choose from:

  1. : Add key and value to
  2. : This is how you get items from
  3. : Remove an item by key from
  4. : Clear all
  5. : Passed a number to retrieve the key of a

: How to store values in

Just as the name implies, this method allows you to store values in the object.

It takes two parameters: a key and a value. The key can be referenced later to fetch the value attached to it.

window.localStorage.setItem('name', 'Obaseki Nosa');

Where is the key and is the value. Also note that can only store strings.

To store arrays or objects, you would have to convert them to strings.

To do this, we use the method before passing to .

const person = {
    name: "Obaseki Nosa",
    location: "Lagos",
}

window.localStorage.setItem('user', JSON.stringify(person));

: How to get items from

To get items from localStorage, use the method.  allows you to access the data stored in the browser’s object.

accepts only one parameter, which is the , and returns the as a string.

To retrieve a user key:

window.localStorage.getItem('user');

This returns a string with value as:

“{“name”:”Obaseki Nosa”,”location”:”Lagos”}”

To use this value, you would have to convert it back to an object.

To do this, we make use of the method, which converts a JSON string into a JavaScript object.

JSON.parse(window.localStorage.getItem('user'));

: How to delete sessions

To delete local storage sessions, use the method.

When passed a key name, the method removes that key from the storage if it exists. If there is no item associated with the given key, this method will do nothing.

window.localStorage.removeItem('name');

: How to delete all items in

Use the method to delete all items in .

This method, when invoked, clears the entire storage of all records for that domain. It does not receive any parameters.

window.localStorage.clear();

: How to get the name of a key in

The method comes in handy in situations where you need to loop through keys and allows you to pass a number or index to to retrieve the name of the key.

var KeyName = window.localStorage.key(index);

Использование HTML5-хранилища

HTML5-хранилище базируется на именах пар ключ/значение. Вы сохраняете информацию, основываясь на имени ключа, а затем можете получить эти данные с тем же ключом. Имя ключа это строка. Данные могут быть любого типа, который поддерживает JavaScript, включая строки, логические, целые числа или числа с плавающей запятой. Однако в действительности данные хранятся в виде строки. Если вы сохраняете и извлекаете не строки, то надо будет использовать такие функции как parseInt() или parseFloat(), чтобы перевести полученные данные в корректные типы JavaScript.

Интерфейс хранилища {
  Получить через getItem(ключ);
  Установить через setItem(ключ, данные);
};

Вызов setItem() с существующим именем ключа молча перепишет предыдущее значение. Вызов getItem() с несуществующим ключом вернет NULL, а не вызовет исключение.

Подобно другим объектам JavaScript вы можете обращаться к объекту localStorage как к ассоциативному массиву. Вместо использования методов getItem() и setItem(), вы можете просто указать квадратные скобки. Например, этот фрагмент кода

var foo = localStorage.getItem(«bar»);
// …
localStorage.setItem(«bar», foo);

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

var foo = localStorage;
// …
localStorage = foo;

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

Интерфейс хранилища {
  Удалить через removeItem(ключ);
  clear();
}

Вызов removeItem() с несуществующим ключом ничего не вернет.

Наконец, есть свойство для получения общего количества значений в области хранения и для перебора всех ключей по индексу (получает имя каждого ключа).

Интерфейс хранилища {
  length
  Получить key(целое неотрицательное число);
}

Если при вызове key() индекс лежит не в диапазоне от 0 до (length-1), то функция вернет null.

Usage

CoffeeScript

unless localStorage?
  {LocalStorage} = require('../')  # require('node-localstorage') for you
  localStorage = new LocalStorage('./scratch')

localStorage.setItem('myFirstKey', 'myFirstValue')
console.log(localStorage.getItem('myFirstKey'))
# myFirstValue

localStorage._deleteLocation()  # cleans up ./scratch created during doctest

ReactJs

Open or create and add these two lines:

// /src/setupTests.js
import { LocalStorage } from "node-localstorage";

global.localStorage = new LocalStorage('./scratch');

JavaScript

if (typeof localStorage === "undefined" || localStorage === null) {
  var LocalStorage = require('node-localstorage').LocalStorage;
  localStorage = new LocalStorage('./scratch');
}

localStorage.setItem('myFirstKey', 'myFirstValue');
console.log(localStorage.getItem('myFirstKey'));

Polyfill on Node.js

Polyfil your node.js environment with this as the global localStorage when launching your own code

node -r node-localstorage/register my-code.js

Usage

Write to Storage

This can be anywhere from within your application.

import React from 'react';
import { writeStorage } from '@rehooks/local-storage';

let counter = ;

const MyButton = () => (
  <button onClick={_ => writeStorage('i', ++counter)}>
    Click Me
  <button>
);

Read From Storage

This component will receive updates to itself from local storage.

Javascript:

import React from 'react';
import { useLocalStorage } from '@rehooks/local-storage';

function MyComponent() {
  const counterValue = useLocalStorage('i'); // send the key to be tracked.
  return (
    <div>
      <h1>{counterValue}<h1>
    <div>
  );
}

Typescript:

import React from 'react';
import { useLocalStorage } from '@rehooks/local-storage';

function MyComponent() {
  const counterValue = useLocalStorage<number>('i'); // specify a type argument for your type
  // Note: Since there was no default value provided, this is potentially null.
  return (
    <div>
      <h1>{counterValue}<h1>
    <div>
  );
}

Optionally use a default value

import React from 'react';
import { useLocalStorage } from '@rehooks/local-storage';

function MyComponent() {
  // Note: The type of user can be inferred from the default value type
  const user = useLocalStorage('user', { name: 'Anakin Skywalker' });
  return (
    <div>
      <h1>{user.name}<h1>
    <div>
  );
}

Delete From Storage

You may also delete items from the local storage as well.

import { writeStorage, deleteFromStorage } from '@rehooks/local-storage';

writeStorage('name', 'Homer Simpson'); // Add an item first

deleteFromStorage('name'); // Deletes the item

const thisIsNull = localStorage.getItem('name'); // This is indeed null

Using With Context

It is advisable to use this hook with context if you want to have a properly
synchronized default value. Using in two different components
with the same key but different default values can lead to unexpected behaviour.

Using Context will also prevent components from rendering and setting
default values to the localStorage when you just want them to be deleted from localStorage
(assuming the context provider also does not re-render).

import React, { createContext, useContext } from 'react';
import { useLocalStorage } from '@rehooks/local-storage';

const defaultProfile = { name: 'Spongekebob' };
const defaultContextValue = defaultProfile, () => {}, () => {};

const ProfileContext = createContext(defaultContextValue);

export const ProfileProvider = ({ children }) => {
  const ctxValue = useLocalStorage('profile', defaultProfile);
  return (
    <ProfileContext.Provider value={ctxValue}>
      {children}
    <ProfileContext.Provider>
  );
};

const useProfile = () => useContext(ProfileContext);

const App = () => {
  const profile = useProfile();
  return <h1>{profile && profile.name}<h1>;
};

export default () => {
  return (
    <ProfileProvider>
      <App >
    <ProfileProvider>
  );
};

Слежение за областью HTML5-хранилища

Если вы хотите программно отслеживать изменения хранилища, то должны отлавливать событие storage. Это событие возникает в объекте window, когда setItem(), removeItem() или clear() вызываются и что-то изменяют. Например, если вы установили существующее значение или вызвали clear() когда нет ключей, то событие не сработает, потому что область хранения на самом деле не изменилась.

Событие storage поддерживается везде, где работает объект localStorage, включая Internet Explorer 8. IE 8 не поддерживает стандарт W3C addEventListener (хотя он, наконец-то, будет добавлен в IE 9), поэтому, чтобы отловить событие storage нужно проверить, какой механизм событий поддерживает браузер (если вы уже проделывали это раньше с другими событиями, то можете пропустить этот раздел до конца). Перехват события storage работает так же, как и перехват других событий. Если вы предпочитаете использовать jQuery или какую-либо другую библиотеку JavaScript для регистрации обработчиков событий, то можете проделать это и со storage тоже.

if (window.addEventListener) {
  window.addEventListener(«storage», handle_storage, false);
} else {
  window.attachEvent(«onstorage», handle_storage);
};

Функция обратного вызова handle_storage будет вызвана с объектом StorageEvent, за исключением Internet Explorer, где события хранятся в window.event.

function handle_storage(e) {
  if (!e) { e = window.event; }
}

В данном случае переменная e будет объектом StorageEvent, который обладает следующими полезными свойствами.

Объект StorageEvent
Свойство Тип Описание
key string Ключ может быть добавлен, удален или изменен.
oldValue любой Предыдущее значение (если переписано) или null, если добавлено новое значение.
newValue любой Новое значение или null, если удалено.
url* string Страница, которая вызывает метод, приведший к изменению.

* Примечание: свойство url изначально называлось uri и некоторые браузеры поддерживали это свойство перед изменением спецификации. Для обеспечения максимальной совместимости вы должны проверить существует ли свойство url, и если нет проверить вместо него свойство uri.

Событие storage нельзя отменить, внутри функции обратного вызова handle_storage нет возможности остановить изменение. Это просто способ браузеру сказать вам: «Эй, это только что случилось. Вы ничего не можете сделать, я просто хотел, чтобы вы знали».

Шаг 2: Получаем данные из localStorage

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

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

componentDidMount() {
const rememberMe = localStorage.getItem(‘rememberMe’) === ‘true’;
const user = rememberMe ? localStorage.getItem(‘user’) : »;
this.setState({ user, rememberMe });
}

1
2
3
4
5

componentDidMount(){

constrememberMe=localStorage.getItem(‘rememberMe’)===’true’;

constuser=rememberMe?localStorage.getItem(‘user’)»;

this.setState({user,rememberMe});

}

Теперь давайте углубимся в код:

Первым делом мы получаем значение “Remember me”

Уже обратили внимание, что сравнение идёт со строкой “true”? Это потому что  хранит данные как строки. Таким образом нам надо получить хранящееся значение и запарсить его обратно в логический тип данных, перед его непосредственным использованием

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

Далее мы получаем имя пользователя, но только в том случае, если  имеет значение .

И под конец мы назначаем эти значения стейту компонента.

И вот она магия!

И ещё совет

Как я говорил выше,  может хранить данные только в виде строк. Если вы имеете дело только с несколькими сохраненными значениями, то это не очень то и большая проблема. Но если вы хотите воспользоваться  на полную катушку в вашем приложении, то я очень советую взять на вооружение библиотеку, которая облегчит сохранение и получение данных, обойдя стороной такие процессы, как парсинг и обращение в строку. В этом деле идеально может подойти проверенная в боях Store.js. Это моя личная рекомендация.

Заключение

В React  очень просто использовать. Просто определите в каких случаях лучше сохранять и получать свои данные. Этот момент будет меняться от компонента к компоненту.

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

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

Открыть базу данных

Для начала работы с IndexedDB нужно открыть базу данных.

Синтаксис:

  • – название базы данных, строка.
  • – версия базы данных, положительное целое число, по умолчанию (объясняется ниже).

У нас может быть множество баз данных с различными именами, но все они существуют в контексте текущего источника (домен/протокол/порт). Разные сайты не могут получить доступ к базам данных друг друга.

После этого вызова необходимо назначить обработчик событий для объекта :

  • : база данных готова к работе, готов «объект базы данных» , его следует использовать для дальнейших вызовов.
  • : не удалось открыть базу данных.
  • : база открыта, но её схема устарела (см. ниже).

IndexedDB имеет встроенный механизм «версионирования схемы», который отсутствует в серверных базах данных.

В отличие от серверных баз данных, IndexedDB работает на стороне клиента, в браузере, и у нас нет прямого доступа к данным. Но когда мы публикуем новую версию нашего приложения, возможно, нам понадобится обновить базу данных.

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

Это событие также сработает, если базы данных ещё не существует, так что в этом обработчике мы можем выполнить инициализацию.

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

Когда мы публикуем вторую версию:

Таким образом, в мы обновляем базу данных. Скоро подробно увидим, как это делается. А после того, как этот обработчик завершится без ошибок, сработает .

После у нас есть объект базы данных в , который мы будем использовать для дальнейших операций.

Удалить базу данных:

А что, если открыть предыдущую версию?

Что если мы попробуем открыть базу с более низкой версией, чем текущая? Например, на клиенте база версии 3, а мы вызываем .

Возникнет ошибка, сработает .

Такое может произойти, если посетитель загрузил устаревший код, например, из кеша прокси. Нам следует проверить и предложить ему перезагрузить страницу. А также проверить наши кеширующие заголовки, убедиться, что посетитель никогда не получит устаревший код.

Раз уж мы говорим про версионирование, рассмотрим связанную с этим небольшую проблему.

Проблема заключается в том, что база данных всего одна на две вкладки, так как это один и тот же сайт, один источник. И она не может быть одновременно версии 1 и 2. Чтобы обновить на версию 2, все соединения к версии 1 должны быть закрыты.

Чтобы это можно было организовать, при попытке обновления на объекте базы возникает событие . Нам нужно слушать его и закрыть соединение к базе (а также, возможно, предложить пользователю перезагрузить страницу, чтобы получить обновлённый код).

Если мы его не закроем, то второе, новое соединение будет заблокировано с событием вместо .

Код, который это делает:

Здесь мы делаем две вещи:

  1. Добавляем обработчик после успешного открытия базы, чтобы узнать о попытке параллельного обновления.
  2. Добавляем обработчик для ситуаций, когда старое соединение не было закрыто. Такого не произойдёт, если мы закрываем его в .

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

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

Используем localStorage в React

Перевод How to use localStorage with React

Как использовать преимущества localStorage в React? Да легко! В этой статье вы узнаете об удобстве применения локального хранилища в React приложениях.

Сердцем каждого приложения на React является его стейт. Компоненты могут иметь свой собственный внутренний стейт и поверьте мне, несмотря на всю их простоту, вы можете делать с ними много невероятно крутых вещей. Но давайте представим, что вы создаёте приложение и в какой-то момент вам надо локально сохранить данные от пользователя или даже сохранить весь стейт для одного или нескольких других компонентов. И тут, возможно, вам захочется понять, а как же можно использовать  в React приложении? Что же, начнем с того, что  тут вам уже не помощник, но не переживайте, все будет довольно просто. Читаем дальше.

Веб хранилище

Оно создано для того, чтобы хранить данные в браузере и оно потерпело значительное количество позитивных улучшений в сравнении со своим предшественником — кукисами. Сначала оно было как HTML5 API, ну а потом переросло уже в независимую рабочую единицу. Хранилище поддерживается буквально каждым современным браузером и даже некоторыми старичками, например такими как IE8. Веб хранилище реализовано двумя способами: первый — , постоянное хранилище данных, которое можно сравнить с постоянными кукисами, второе —, хранилище существующее только на время определенной сессии и на определенный период времени. Хоть эта статья и работает с , но вы также можете применить все описанные методики и на sessionStorage.

Наш компонент для рабочего примера

Итак, нам нужен компонент на котором мы будем все испытывать. Тут я думаю, что страница логина с опцией “Remember me” подойдет идеально. Для простоты и понятности, мы не будем добавлять поле пароля. Давайте посмотрим на метод :

render() {
return (
&lt;form onSubmit={this.handleFormSubmit}&gt;
&lt;label&gt;
User: &lt;input name=»user» value={this.state.user} onChange={this.handleChange}/&gt;
&lt;/label&gt;
&lt;label&amp;gt;
&amp
;lt;input name=»rememberMe» checked={this.state.rememberMe} onChange={this.handleChange} type=»checkbox»/&gt; Remember me
&lt;/label&gt;
&lt;button type=»submit»&gt;Sign In&lt;/button&gt;
&lt;/form&gt;
);
}

1
2
3
4
5
6
7
8
9
10
11
12
13

render(){

return(

&lt;form onSubmit={this.handleFormSubmit}&gt;

&lt;label&gt;

User&lt;input name=»user»value={this.state.user}onChange={this.handleChange}&gt;

&lt;label&gt;

&lt;label&gt;

&lt;input name=»rememberMe»checked={this.state.rememberMe}onChange={this.handleChange}type=»checkbox»&gt;Remember me

&lt;label&gt;

&lt;button type=»submit»&gt;Sign In&lt;button&gt;

&lt;form&gt;

);

}

export default class SignIn extends Component {
state = {
user: »,
rememberMe: false
};

handleChange = (event) =&gt; {
const input = event.target;
const value = input.type === ‘checkbox’ ? input.checked : input.value;

this.setState({ : value });
};

handleFormSubmit = () =&gt; {};

render() { /*…*/ }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

exportdefaultclassSignInextendsComponent{

state={

user»,

rememberMefalse

};

handleChange=(event)=&gt;{

constinput=event.target;

constvalue=input.type===’checkbox’?input.checkedinput.value;

this.setState({input.namevalue});

};

handleFormSubmit=()=&gt;{};

render(){/*…*/}

}

Если вы заполните инпут для пользователя, а потом кликните на “Remember Me” чекбокс и под конец кликните на кнопку “Sign In”, то вы заметите, что форма снова опустеет:

Это вполне нормальное поведение. Теперь мы должны узнать как же нам использовать  в React и заставить форму работать должным образом.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector