
рдореЗрд░рд╛ рдирд╛рдо рд╡рд┐рдЯрд╛рд▓реА рд░рд┐рдЬрд╝реЛ рд╣реИ, рдореИрдВ рдПрдореНрдкрд▓реАрдлрд░ рдореЗрдВ рдПрдХ рд╡рд░рд┐рд╖реНрда рдлреНрд░рдВрдЯ-рдПрдВрдб рдбреЗрд╡рд▓рдкрд░ рд╣реВрдВред рдореБрдЭреЗ рд╕рд╛рдЭрд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдо рд╡реЗрдм рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рд▓реЙрдЧрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░рддреЗ рд╣реИрдВ: рд╣рдо рдкреГрд╖реНрда рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдмрд┐рдирд╛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдбреЗрдЯрд╛ рдПрдХреНрд╕рдЪреЗрдВрдЬ, рддреНрд░реБрдЯрд┐ рд╕реВрдЪрдирд╛рдУрдВ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЯреИрдм рдХреЗ рдмреАрдЪ рд╕рдВрдЪрд╛рд░ рдФрд░ Redux рдХреЗ рд╕рд╛рде рдПрдХреАрдХрд░рдгред
Amplifer рд╕рд╛рдорд╛рдЬрд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдкрд░ рдкреНрд░рдХрд╛рд╢рди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реЗрд╡рд╛ рд╣реИред рдкреГрд╖реНрда рдХреЛ рдкреБрдирдГ рд▓реЛрдб рдХрд┐рдП рдмрд┐рдирд╛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдЬрд▓реНрджреА рдФрд░ рдордЬрд╝рдмреВрддреА рд╕реЗ рд╕реВрдЪрд┐рдд рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рдерд╛: рдпрджрд┐ рдЕрдЪрд╛рдирдХ рдЫрд╡рд┐ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рдерд╛, рддреЛ VKontakte API рдЧрд┐рд░ рдЧрдпрд╛, рдпрд╛ рдлреЗрд╕рдмреБрдХ рдиреЗ рдлрд┐рд░ рд╕реЗ рдкреЛрд╕реНрдЯ рдкреНрд░рдХрд╛рд╢рд┐рдд рдирд╣реАрдВ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред рдЖрдЧреЗ рджреЗрдЦрддреЗ рд╣реБрдП, рдореИрдВ рдХрд╣реВрдВрдЧрд╛ рдХрд┐ рд╣рдордиреЗ рдкреНрд░рдХрд╛рд╢рдиреЛрдВ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рдиреЗ рдФрд░ рдЖрд░рдПрд╕рдПрд╕ рд╕реЗ рдХреНрд░реЙрд╕-рдкреЛрд╕реНрдЯрд┐рдВрдЧ рдкреЙрдкрдЕрдк рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд▓реЙрдЧрдХреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рдИ рд╣реИред рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ, рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдХрд┐ рд╣рдо рдЙрдкрд▓рдмреНрдз рд╕рдорд╛рдзрд╛рдиреЛрдВ рд╕реЗ рд╕рдВрддреБрд╖реНрдЯ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдереЗред
рд╕рдВрднрд╛рд╡рд┐рдд рд╕рдорд╛рдзрд╛рди: WebSocket, Firebase рдФрд░ Swarm.js
рдЖрдорддреМрд░ рдкрд░, WebSocket рдХрд╛ рдЙрдкрдпреЛрдЧ рдСрдЯреЛ-рдЕрдкрдбреЗрдЯ рдЬрд╛рдирдХрд╛рд░реА рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рдХреЗ рд╕рд╛рде, рдЖрдкрдХреЛ рд╣рд░ рдкрд▓ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рдЖрдкрдХреЛ рдкрд╛рд░рдВрдкрд░рд┐рдХ HTTP рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд╕рд╛рде рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рд╣реЗрдбрд░ рдХрд╛ рдЖрдХрд╛рд░ рдЫреЛрдЯрд╛ рд╣реЛрдЧрд╛ред рд╣рд╛рд▓рд╛рдБрдХрд┐, WebSocket рдХреЗ рдиреБрдХрд╕рд╛рди рд╣реИрдВ:
- . , , , . , : , ;
- , . ;
- , , ;
- , (CRDT), .
Firebase, , тАФ . Firebase CRDT, Redux . CRDT Swarm.js, Redux , .
Logux
, тАФ Logux. , Redux, CRDT . - , API-: , .
, , ┬л ┬╗. :
imports-api.js
update (project, id, data) {
return put(project, `settings/imports/${ id }`, convert(data))
}
imports.js
onUpdate (projectId, importId, changed) {
return dispatch({
projectId,
importId,
import: changed,
type: 'amplifr/imports/update'
})
}
:
imports.js
let dispatch = useDispatch()
let onUpdate = (projectId, importId, changed) => dispatch.sync({
projectId,
importId,
import: changed,
type: 'amplifr/imports/update'
}, { channels: ['imports/' + projectId] })
sync
dispatch
, , , . , Logux .
Logux

тАФ . , . , .
, Logux-. .
Logux Redux. Redux createStore
. Logux, ┬л┬╗ createLoguxCreator
:
import { createLoguxCreator } from '@logux/redux'
let createStore = createLoguxCreator({
credentials: loguxToken,
subprotocol: '0.6.5',
userId,
server: 'wss://logux.amplifr.com'
})
let store = createStore(reducers)
store.client.start()
createLoguxCreator
:
- . , . gon;
- Logux-;
- . , , .
Logux- , . , - posts/1
, . , WebSocket.
? тАФ , , posts/1
. subscribe
тАФ :
import useSubscription from '@logux/redux/use-subscription'
let Notices = props => {
let isSubscribing = useSubscription([`projects/${ props.id }`])
if (isSubscribing) {
return <Loader />
} else {
}
}
тАФ , HTTP- Redux- Logux, Logux- :
def schedule_logux
LoguxNotificationWorker.perform_async(
{ type: 'amplifr/notices/add', notice: Logux::NoticePresenter.new(notice).to_json },
channels: ["projects/#{project.id}"]
)
end
, . - , , . , :
import { useDispatch } from 'react-redux'
let dispatch = useDispatch()
let onNoticeHide = noticeId => dispatch.sync({
type: 'amplifr/notices/hide',
noticeId
}, {
channels: [`projects/${ projectId }`]
})
, , Logux:

-
Logux , . , - , . , . , , , .
Logux . ┬л┬╗ , , localStorage. , Firefox Safari localStorage! Logux , , . , .
, , Logux , , . , , .
, Logux, .
Logux

, Logux, . тАФ , :
let PostEditor = { isApprovable, postId, тАж } => {
let isSubscribing = useSubscription(isApprovable ? [`posts/${ postId }`] : [])
if (isSubscribing) {
return <Loader />
} else {
}
}
notes
:
import { useDispatch, useSelector } from 'react-redux'
let dispatch = useDispatch()
let notes = useSelector(notes.filter(note => note.postId === postId))
let onNoteAdd = note => dispatch.sync({
type: 'amplifr/notes/add',
note
}, {
channels: [`posts/${ postId }`]
})
. , :
export default function notes (state = [], action) {
if (action.type === 'amplifr/notes/add') {
return state.concat([action.note])
} else if (action.type === 'amplifr/posts/close') {
return state.filter(i => i.postId !== action.postId)
} else {
return state
}
}
. Logux, .

, @subscribe
. , isSubscribing: true
. , , . .
, . , squid 3, WebSocket ( Logux WebSocket). , , . тАФ .
, Logux AJAX-. , ┬л┬╗ ┬л┬╗ Firefox.
AJAX Logux RSS. RSS- . RSS-, .

. :
import { useDispatch } from 'react-redux'
let dispatch = useDispatch()
let onCreate = (projectId, importId, import) => {
return dispatch.sync({
importId,
import,
type: 'amplifr/imports/add'
}, { channels: ['imports/' + projectId] })
}
let onUpdate = (projectId, importId, changed) => {
return dispatch.sync({
importId,
changed,
type: 'amplifr/imports/update'
}, { channels: ['imports/' + projectId] })
}
, , , Logux Optimitstic UI тАФ . , , . - , .

┬л┬╗ .
┬л┬╗, , RSS- . , . Logux (dispatch.sync(тАж).catch(тАж)
), . -, , .
: catch()
JSON, try { JSON.parse(тАж) } catch { тАж }
. .
Logux ?
Logux WebSocket, , SPA . , . , , :
import status from '@logux/client/status'
let connected = false
status(store.client, state => {
if (state === 'synchronized') connected = true
}
setTimeout(() => {
if (!connected) {
sentry.track(new Error('No Logux connection for 10 minutes'))
}
}, 60 * 1000)
100 , . , - , :

, WebSocket: -, , , , , AdBlocker Kaspersky Protection. , , , Logux, .
Logux ,
Logux , . , , . RSS-, , . - , , , , .
, . тАФ Logux. -. , , , , :
import log from '@logux/client/log'
let store = createStore(reducers)
log(store.client)
window.store = store
:
- RSS- ;
- , ;
- RSS-, ;
- ;
- !
:
window.store.client.log.store.created.filter(i => i[0].type === 'amplifr/popups/set')
, - : meta.tab
undefined
. , . , client.id
client.tabId
@logux/redux
id
tabId
. , , Logux , , .
, - ┬л┬╗ Logux, :
Logux : ┬л? , , ?┬╗. , тАФ , , Redux. ┬л ┬╗, , . Logux .

:
- Logux, Redux, CRDT ;
- C Logux , ;
- Logux , ;
- рд▓реЙрдЧрдХреНрд╕ рдореЗрдВ рдЗрд╕рдХреА рдХрдорд┐рдпрд╛рдВ рд╣реИрдВ: рдкреНрд░рдгрд╛рд▓реА рд╕рд░рд▓ рдирд╣реАрдВ рд╣реИ, рдЕрднреА рднреА рдХреАрдбрд╝реЗ рд╣реИрдВ рдФрд░ рд╕рдорд╛рдзрд╛рди рд╣рдореЗрд╢рд╛ рдЬрд▓реНрджреА рдирд╣реАрдВ рдорд┐рд▓рддреЗ рд╣реИрдВ;
- Amplifer рдореЗрдВ, Logux рдХреЗ рдлрд╛рдпрджреЗ рдиреЗ рд╡рд┐рдкрдХреНрд╖ рдХреЛ рдкрдЫрд╛рдбрд╝ рджрд┐рдпрд╛ред рд╣рдо рдЙрдкрдпреБрдХреНрдд рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╕рдордп рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдЬрд╛рд░реА рд░рдЦрдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВред

тМШтМШтМШ
рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рд▓реЛрдЧрдХреНрд╕ рдЖрдкрдХреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдЖрдкрдХреЗ рдХреЛрдИ рдкреНрд░рд╢реНрди рд╣реИрдВ, рддреЛ рдХреГрдкрдпрд╛ рдореБрдЭреЗ рдЯреНрд╡рд┐рдЯрд░ рдкрд░ рдпрд╛ рдореЗрд▓ рд╕реЗ рд▓рд┐рдЦреЗрдВ ред
рдЗрд╕ рд▓реЗрдЦ рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХреЗ рд▓рд┐рдП рдЕрд▓реЗрдХреНрдЬреЗрдВрдбрд░ рдорд╛рд░рдлрд┐рдЯрд┐рди рдФрд░ рдЖрдВрджреНрд░реЗрдИ рд╕реАрдЯрдирд┐рдХ рдХрд╛ рдзрдиреНрдпрд╡рд╛рдж ред