Skip to content
This repository has been archived by the owner on Jul 15, 2020. It is now read-only.

Provide examples of an isometric store #49

Open
iaincollins opened this issue Oct 16, 2017 · 0 comments
Open

Provide examples of an isometric store #49

iaincollins opened this issue Oct 16, 2017 · 0 comments

Comments

@iaincollins
Copy link
Owner

The goal is to show how to create a simple store, that supports with universal rendering.

Redux is the common approach taken for this, and unlike MobX it doesn't require decorator support, but Redux generally requires more code to do the same thing and is not always as easy to follow the logic.

There was a previous example of a Clock that use Redux and supported server side rendering but it wasn't a great introductory example and didn't cover a use case that translated well for most people so I removed it.

I'm considering adding a store that uses MobX to the project, as in the below example, but I appreciate more people would probably like a Redux example (in this case the same working example in both would be ideal!).

What's missing from the below example is meaningful Server Side Rendering support. The store allows a default value to be passed in (e.g. from a session) but it would make sense if there was a flow that could read directly from the server when a store was rendering on the server.

Maybe I need to shortlist some real use cases to come up with a meaningful practical example. Ideas for practical examples of stores welcome!

Most of the use cases I have in production (in real world projects) are fetching data from REST APIS and I find simple JavaScript classes are simpler to implement and use (and less code!), especially in conjunction with Web Storage APIs to cache data.

I think the only place I actually bother with a Store in production is to use socket.io with React in a graceful way, to avoid creating a new Socket and to track when events happen on a Socket.

Note: I considered making the Session component a Store as an example, but like a lot of other cases I have it would have added complexity and code for little to no benefit so decided against it.

Config required to use mobx with Next.js (as it relies on decorators) in .babelrc:

{
"presets": [
    "next/babel"
  ],
  "plugins": ["transform-decorators-legacy"]
}

Code for a Counter store in stores/counter.js:

import { observable, action } from 'mobx'

let store = null

class Store {
  @observable counter = 0
  
  // Initalize store with default values if passed any
  constructor ({
      counter = 0
    }) {
    this.counter = counter
  }

  @action
  increment () {
    this.counter++
  }

  @action 
  decrement () {
    this.counter--
  }

  @action
  startAutoInc () {
    this.timer = setInterval(() => { 
      this.counter++
    }, 1000)
  }

  @action
  stopAutoInc () {
    clearInterval(this.timer)
    this.timer = null
  } 

  @action 
  autoIncIsRunning () {
    return (this.timer) ? true : false;
  }
  
  @action
  resetCounter () {
    this.counter = 0
  }
}

export function initStore(defaults = {}) {
  if (typeof window === 'undefined') {
    return new Store(defaults)
  } else {
    if (store === null) {
      store = new Store(defaults)
    }
    return store
  }
}

Code for a component using the Counter store in components/counter.js:

import React from 'react'
import { observer } from 'mobx-react'
import { Store, initStore } from '../stores/counter'

@observer
export default class extends React.Component {

  constructor(props) {
    super(props)
    this.store = initStore(this.props.store) // Default value defined in props
    this.handleStartStop = this.handleStartStop.bind(this)
  }

  handleStartStop () {
    this.store.autoIncIsRunning() ? this.store.stopAutoInc() : this.store.startAutoInc()
  }

  render () {
    return (
      <div>
        <div className='counter'>
          <span>{this.store.counter}</span>
        </div>
        <div className='buttons'>
          <button onClick={() => this.store.increment()}>Increment</button>
          <button onClick={() => this.store.decrement()}>Decrement</button>
          <button onClick={this.handleStartStop}>{this.store.autoIncIsRunning() ? 'Stop' : 'Start'} Auto-increment</button>
          <button onClick={() => this.store.resetCounter()}> Reset</button>
        </div>
        <style jsx>{`
        .counter {
          background: black;
          color: white;
          padding: 20px;
          text-align: center;
        }
      `}</style>
      </div>
    )
  }
}
@iaincollins iaincollins changed the title Provide examples of an isometric stores Provide examples of an isometric store Oct 16, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant