- PVSM.RU - https://www.pvsm.ru -
Современный веб позволяет решать часть задач которые раньше были прерогативой нативных мобильных приложений. Мы с вами создадим веб-приложение (сайт) которое будет загружаться и сохранит полную функциональность даже в отсутствии интернета, а при его появлении автоматически синхронизируется с сервером. На мобильном устройстве для такого приложения достаточно создать ярлык и в плане автономности мы получим аналог нативного приложения.
Мы напишем подобие todo-листа, с одним отличием: "выполненные" задачи будут не удаляться, а переноситься в конец списка и по мере решения остальных задач всплывать вверх. Такой список удобно использовать для повторяющихся вещей, таких как различные спортивные активности, развлечения, еда и т.п. Одна моя социально-реализованная знакомая использует его, чтобы равномерно поддерживать контакт с многочисленной популяцией своей френдзоны.
То, что получится в результате можно посмотреть тут [1]. Попробуйте внести некоторые изменения, закрыть вкладку, отключить интернет и снова открыть сайт. Вы обнаружите, что он открывается и сохраняет полную функциональность. Если вы залогинитесь на разных устройствах и внесёте изменения в оффлайне, по восстановлении соединения изменения синхронизируются интуитивно ожидаемым образом.
Вы удивитесь насколько мало кода нам потребуется для реализации этого функционала.
Чтобы не засорять текст очередными настройками вебпака, я создал репу [2] с готовыми настройками. Просто склонируйте её и переключитесь на часть 0: git checkout part0
. Ключевые точки на которые стоит обратить внимание:
npm start
— запускает hoodie-сервер и сборку приложения вебпаком в режиме watch (пересборки при изменении)public/index.html
— именно то, что вы подумали, тут мы создаём корневой div приложения и подключаем собранный вебпаком бандлsrc/index.js
— точка входа в приложение, тут мы рендерим корневую компоненту: ReactDOM.render(<App />
src/App.js
— наша пока единственная компонента, тут мы и начнём писать код в следующей частиПопробуйте запустить сервер. Когда вебпак скажет, что всё готово, по адресу http://localhost:8000/ [3] вы должны увидеть симпатичную шапку сайта.
Для функционирования приложения в оффлайн-режиме, нам потребуется где-то хранить данные и как-то синхронизировать их между устройствами. Pouchdb [4] подходит для этого идеально. Но мы и с ней будем работать не напрямую а через обёртку Hoodie [5], которая умеет авторизацию. Давайте подключим её в src/App.js
:
import Hoodie from '@hoodie/client'
const hoodie = new Hoodie()
Теперь создадим компоненту для добавления loop-а (отдельного todo-листа):
import React from 'react'
import TextField from 'material-ui/TextField'
import RaisedButton from 'material-ui/RaisedButton'
export default class AddLoop extends React.Component {
constructor(props) {
super(props)
this.state = {
title: ''
}
}
handleTitleChange = (e) => this.setState({title: e.target.value})
handleSubmit = (e) => {
e.preventDefault()
this.props.store.add({
type: 'loop',
title: this.state.title
})
this.setState({title: ''})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<TextField
hintText="New loop"
value={this.state.title}
onChange={this.handleTitleChange}
style={{marginRight: '10px'}}
/>
<RaisedButton label="Add" type="submit" primary={true} />
</form>
);
}
}
Суть здесь заключена в строчке this.props.store.add
. Где store
— это hoodie.store
который нам нужно передать в свойствах компоненты при рендеренге её в App.js
:
render() {
...
<AddLoop store={hoodie.store} />
Давайте теперь отобразим сохранённые в базу документы. В App.js
мы добавим метод loadLoops
:
constructor(props) {
super(props);
this.state = {
loops: []
};
this.loadLoops();
}
loadLoops = () => {
hoodie.store.findAll(doc => doc.type == 'loop')
.then(loops => this.setState({loops}))
}
Нам понадобился конструктор, в котором мы инициализируем state
и инициируем загрузку документов. В hoodie.store.findAll
мы передаём фильтр для нужных документов и получаем промис, в котором просто записываем полученные документы в state
.
Давайте теперь отрисуем их, добавив в render()
:
{this.state.loops.map(loop => (
<Paper key={loop.id} zDepth={2} style={{maxWidth: 400, margin: '20px auto'}}>
<h3 style={{padding: 15}}>{loop.title}</h3>
</Paper>
))}
Теперь вы должны видеть список добавленных loop-ов. Однако при добавлении новых они появятся в списке только при перезагрузке страницы. Давайте исправим это.
Весь код этого пункта будет состоять из добавления пары строчек в наш App.js
:
componentDidMount() {
hoodie.store.on('change', this.loadLoops);
}
Теперь при добавлении loop-ов они будут автоматически появляться в списке. Причём независимо от того, каким образом изменилась база данных. Это важно — даже если изменения произошли в ходе синхронизации с другим устройством, наш коллбэк сработает.
Из логики работы с бд становится понятно почему среди обилия браузерных шаблонизаторов был выбран реакт. В ответ на каждое изменение бд мы будем просто перезагружать всё состояние. И будь на месте реакта любимый мной vue.js он перерендерил бы весь dom. А это не просто медленно, представьте вы заполняете форму и в этот момент другое устройство инициирует изменение бд — форма перерисована, ваши изменения потеряны. Тогда как реакт с его виртуальным dom аккуратно перерисует изменившиеся детали и даже фокуса в вашей форме не собьёт.
Сегодня мы научились взаимодействовать с браузерной бд. В следующей части мы настроим серверную бд и прикрутим авторизацию. Буду рад любым вашим замечаниям / исправлениям / пожеланиям. Код этой части доступен тут: https://github.com/imbolc/action-loop [2] под тегом part1
.
Автор: Imbolc
Источник [6]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/184821
Ссылки в тексте:
[1] посмотреть тут: https://action-loop.com/
[2] репу: https://github.com/imbolc/action-loop
[3] http://localhost:8000/: http://localhost:8000/
[4] Pouchdb: https://pouchdb.com/
[5] Hoodie: http://docs.hood.ie/camp/
[6] Источник: https://habrahabr.ru/post/309166/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.