loading...
NERDSLABS

Frontend store with the state on the elixir backend.

drozdzynski profile image Krystian Drożdżyński ・2 min read

I would like to present a library which moves frontend stores to elixir backend, named Stex. Whole communication going through WebSocket.

Important: Stex is under active development. Report issues and send proposals here.

Currently, the entire state of the store is being sent on each mutation, sending diffs of state is planned.

Basic usage

Installation

Add stex to deps in mix.exs:

defp deps do
  [
    {:stex, git: "https://github.com/nerdslabs/stex"},
  ]
end

Also you need to add stex to package.json dependencies:

{
  "stex": "file:../deps/stex",
}

Add stex websocket handler

You need to add handler Stex.Socket.Handler to cowboy dispatch.

Phoenix:
Example based on Phoenix guides

config :exampleapp, ExampleApp.Endpoint,
  http: [
    dispatch: [
      {:_,
       [
         {"/stex", Stex.Socket.Handler, []},
         {:_, Phoenix.Endpoint.Cowboy2Handler, {ExampleApp.Endpoint, []}}
       ]}
    ]
  ]

Cowboy:

:cowboy_router.compile([
    {:_, [
      # ...
      {"/stex", Stex.Socket.Handler, []},
      # ...
    ]}
  ])

Create store

To create a store you need to create new elixir module with init/2 which is called when a page is loaded, every time websocket is connected it generates session_id and passes it as the first argument, params are from Javascript store declaration. Next, you can declare mutation/5 where the first argument is mutation name, second is data passed to mutation, next two params are same like in init/2, the last one is the current state of the store.

defmodule ExampleApp.Store.Counter do
  use Stex.Store

  def init(session_id, params) do
    0
  end

  def mutation("increase", _data, _session_id, _params, state) do
    state = state + 1

    {:ok, state}
  end

  def mutation("decrease", _data, _session_id, _params, state) do
    state = state - 1

    {:ok, state}
  end

  def mutation("set", [number], _session_id, _params, state) do
    {:ok, number}
  end
end

Connect to store

You have to connect the newly created store with a frontend side to be able to synchronise the state: params are passed as second argument in store init/2 and as third in mutation/5. You can subscribe to changes inside store state by passing option subscribe with function as a value.

import Stex from 'stex'

const store = new Stex({
  store: 'ExampleApp.Store.Counter',
  params: {},
  subscribe: () => {
    const state = store.state
  }
})

Mutate store

You can mutate store from javascript with store instance:

store.mutate("increase")
store.mutate("set", 10)

Or directly from elixir:

Stex.mutate(session_id, store, "increase")
Stex.mutate(session_id, store, "set", [10])

Subscribe to store state changes

You can subscribe to store state changes in javascript with function subscribe:

store.subscribe(() => {
  const state = store.state
})

More info available on Github.

Discussion

pic
Editor guide
Collapse
dmarko484 profile image
David Marko

Thanks for your article and library. Can you elabore more on usecases yout library is supposed to be used for?

Collapse
drozdzynski profile image
Krystian Drożdżyński Author

For example, you can use it on pages with post comments, and on init/2 get the comments from the database and if a someone make a new comment you can update it from the backend with Method Stex.mutate/3, and users which are on this page can see updates instant. Also using methods store.mutate("name", args...) from frontend is faster than using http requests to some backend logic.