@composi/datastore:

getFromLocalStorage

Hydrate DataStore from LocalStorage

If you're using putInLocalStorage to persist a dataStore's state, you can use getFromLocalStorage during page load to hydrate the dataStore with the data saved during the last session.

getFromLocalStorage returns a promise, so it is non-blocking. That also means you'll have to use a then function to do anything with the result. If there is no data in localStorage, or there is any other problem is retrieving it, getFromLocalStorage will throw an error. This means you must always use a conditional check to see if you received any data before trying to use it. To deal with a failure you will have to use a catch function.

import { h, render } from '@composi/core'
import { DataStore } from '@composi/datastore'

// Create empty dataStore:
const dataStore = new DataStore()

// Try to hydrate dataStore from localStorage.
dataStore.getFromLocalStorage()
  .then(data => {
    // Always check that you got something back:
    if (data) {
      // Use the data to set state on the empty dataStore:
      dataStore.setState(prevState => {
        prevState = data
        return prevState
      })
    }
  })

In the above example we hyrdate a dataStore with what was found in localStorage. However, if there was nothing there, you might want to provide some default data. The following example shows how to do that. We introduce a watcher to render a list component. That way, whether state is set with default data or data retrieved from localStorage, the component will render. We also show how to persist changes to dataStore's state with putInLocalStorage.

import { h, render } from '@composi/core'
import { DataStore } from '@composi/datastore'

const refs = {}

function uuid() {
  return Math.random().toString(16).substring(2, 16)
}

// Default data to use.
const fruits = [
  {
    key: 101,
    value: 'Apples'
  },
  {
    key: 102,
    value: 'Oranges'
  },
  {
    key: 103,
    value: 'Bananas'
  }
]

// Create an empty dataStore:
const dataStore = new DataStore()

// Setup a watcher to render the component when state changes:
dataStore.watch('update-list', () => {
  render(<List data={dataStore.state}/>, 'section')
})

// Hydrate dataStore with data from localStorage:
dataStore.getFromLocalStorage()
  .then(data => {
    // If there was data retrieved from localStorage,
    // add it to dataStore, which will trigger the watcher.
    if (data) {
      dataStore.setState(prevState => {
        prevState = data
        return prevState
      })
    }
  })
  // If localStorage has no data,
  // this is the first time loading.
  // In that case give the dataStore some default data.
  .catch(() => {
    dataStore.setState(prevState => {
      prevState = fruits
      return prevState
    })
    dataStore.putInLocalStorage()
  })

// Define component to render.
function List({data}) {
  const createInputRef = input => {
    if (input)
    refs.input = input
  }
  const addItem = () => {
    const value = refs.input && refs.input.value
    if (value) {
      dataStore.setState(prevState => {
        prevState.push({
          key: uuid(),
          value
        })
        return prevState
      })
      refs.input.value = ''
      refs.input.focus()
      // When data is added, save to localStorage.
      dataStore.putInLocalStorage()
        .then(() => console.log('Successfully saved data with new item in localStorage!'))
    } else {
      alert('Please provide a value before submitting.')
    }
  }
  function deleteItem(key) {
    dataStore.setState(prevState => {
      const state = prevState.filter(item => item.key != key)
      return state
    })
    // When an item is deleted, 
    // save new state to localStorage.
    dataStore.putInLocalStorage()
      .then(() => console.log('Successfully persisted removal of item in localStorage!'))
  }
  return (
    <div>
      <p>
        <input onmount={createInputRef} type="text"/>
        <button onclick={addItem}>Add</button>
      </p>
      <ul>
        {
          data.map(item => (
            <li key="item.key">
              <span>{item.value}</span>
              <button onclick={() => deleteItem(item.key)} className='delete-item'>X</button>
            </li>
          ))
        }
      </ul>
    </div>
  )
}