Skip to content
This repository has been archived by the owner on Dec 18, 2019. It is now read-only.

README doesn't mention state persistence #20

Open
SteveALee opened this issue Apr 7, 2017 · 2 comments
Open

README doesn't mention state persistence #20

SteveALee opened this issue Apr 7, 2017 · 2 comments

Comments

@SteveALee
Copy link
Contributor

What are the good patterns for persistence when using onionify

I guess we can hydrate in an initial/default reducer, either in in the top level component or individual components according to your preferences?

How about persisting though?

Or do you think there's no point being prescriptive? Even if this is your view examples would be helpful.

BTW I thought this was a very interesting series on state - https://getpocket.com/a/read/1657730920

@lopsch
Copy link

lopsch commented Apr 8, 2017

If you want to use Local Storage you should have a look at cycle-storageify. Basically you can wrap your main in the storage technology of choice before wrapping it in onionify. I think the general pattern for the storage wrapper is:

  1. Call the to-be-wrapped main with the given sources to get hold of the sinks. I presume there is a sources.onion.state$ stream for the state and a sources.storage stream for access to the storage.
  2. Deserialize the state from the storage and map it to a reducer function being the initial reducer stream (handling fallback state if there is no state in the storage).
  3. The new reducer stream is a merged stream from the initial reducer stream and the reducer stream from the main sinks (sinks.onion).
  4. Map sources.oinion.state$ to a write action for the storage.
  5. The new storage stream for the sink is then the merge from the stream from 4. and the sinks.storage stream.
  6. Return the new sinks object containing all previous untouched streams from the main sinks and the amended sinks.onion from 3. and sinks.storage from 5.

A simplified storageify version could be:

  function storageify (component) {
    return function storageify (sources) {
      // 1.
      const componentSinks = component(sources)

      // 2.
      const initialReducer$ = sources
      .storage
      .local
      .getItem('app')
      .take(1)
      .map(JSON.parse)
      .map(state => function reducer (prevState) {
        if (state) {
          return state
        } else if (prevState) {
          return prevState
        } else {
          return {}
        }
      })

      // 3.
      const reducer$ = componentSinks.onion
      ? xs.merge(initialReducer$, componentSinks.onion)
      : initialReducer$

      // 4.
      const initialState$ = sources
      .onion
      .state$
      .map(JSON.stringify)
      .map(state => ({
        key: 'app',
        value: state
      }))

      // 5.
      const storage$ = componentSinks.storage
      ? xs.merge(initialState$, componentSinks.storage)
      : initialState$

      // 6.
      const sinks = {
        ...componentSinks,
        onion: reducer$,
        storage: storage$
      }

      return sinks
    }
  }

Please someone correct me, if I'm totally wrong.

@SteveALee
Copy link
Contributor Author

@lopsch Thank you, I'd not come across that, only storage drivers (or HTTP with JSON payload).

I'll explore. I think top level persistence will do fine for my use case as performance of deep hierarchy should not be an issue

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants