npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sum.cumo/vue-states

v1.3.2

Published

Component-based Vue.js state management

Downloads

36

Readme

CircleCI Maintainability Test Coverage

Vue States

Vue States is a state management system for Vue.js.

Checkout the examples at https://github.com/JohannesLamberts/vue-states-examples.

You might want to choose to use Vue States for:

  • Simplicity Just this.MyModel.key and this.MyModel.update(payload). No huge API, that exposes implementation details like state, getters, commit, dispatch.Hot Module Replacement and Lazy-Loading made easy.
  • Flexible scopeIt is designed to support application-wide and local state, and can still be hydrated from SSR or localStorage.
  • Learning & refactoringThe state is composed of Vue components. That means: almost no new APIs and patterns to learn, plus seamless refactoring of your application.
  • PowerAll plugins and native Vue capabilities are accessible by design, without any configuration ( this.$router, this.$apollo, created()... ).
  • HistoryIn combination with Vue History you get a detailed view of what's going on, even for complex scenarios, async processes, error tracking and deeply nested call chains.

This package was released just recently. Feedback is highly welcome.

Installation

The plugin can be installed without any further options:

import VueStates from '@sum.cumo/vue-states'
Vue.use(VueStates)

...or with additional configuration:

Vue.use(
  VueStates, 
  {
    // equal to Vue mixins, will be applied to every created model
    mixins: [],

    // a models state will be restored
    // if an old match (same name and modelId) is found
    // can be used to preserve state during hot module replacement 🚀
    // default: false
    restoreOnReplace: process.env.NODE_ENV === 'development', 

    // registers models on the $root instance, same as
    // const app = new Vue({ models: globalModels })
    globalModels,
  }
)

Getting started

Declare

A model is declared like any other vue-component, only that it doesn't contain any template or render option.

import productsGQL from '@/api/queries/fakeProducts.graphql'

export default {
  data() {
    return {
      stage: '',
      products: [],
    }
  },
  
  // created / destroy hooks are invoked 
  created() {
    this.stage = 'created'
    this.loadProducts()
  },
  
  // vuex mutations and actions become just methods
  methods: {
    async loadProducts() {
      this.saveProducts(await this.$api.loadProducts())
    },
    saveProducts(products) {
      this.products = products
    }
  },
  
  // vuex getters become computed
  computed: {
    stageUppercase() {
      return this.stage.toUpperCase()
    },
  },
}

Hosting

A model is a renderless component that is provided by a hosting component. It is available in the hosting component itself and any child component, that injects the model.

import App from '@/models/example'

export default {

  name: 'ExampleHost',
  
  models: {
    // 'App' becomes the models name and the key to reference it
    App,
  },
  
  template: `
  <div>
    <!-- 
      the model is injected on the hosting component 
      and into every child component, that requests it via the inject option
    -->
    {{ App.stageUppercase }}
    <ExampleChild />
  </div>`,
}

Injection

export default {

  name: 'ExampleChild',
  
  injectModels: [
    'App',
  ],
  
  template: `
  <div>
    <!-- properties are reactive -->
    {{App.products.length}} 
    <!-- methods are accessible through the injected object -->
    <button @click="App.refetch" />
  </div>`,
}

History

To keep track of what happens inside the models can check out Vue History, a package that was developed alongside Vue States but not only works for models but for any Vue component.

After installing Vue History you can enable it for all models by setting the history: true option:

import VueHistory from '@sum.cumo/vue-history'
import VueStates from '@sum.cumo/vue-states'

Vue.use(VueHistory)

Vue.use(
  VueStates, 
  { mixins: [ { history: true } ] }
)

State export/import

State can be exported from and imported into the root model registry. The imported state will be used when initializing models with matching name and modelId. The state must therefore be imported before the model is initialized.

const exported = app.$modelRegistry.exportState()
app.$modelRegistry.importState(exported)

Using export/import you can persist state to localStorage or initialize state before Client Side Hydration after SSR.

Filtered Export

The export can be configured to filter which models will be included in the export.

const exported = app.$modelRegistry.exportState({

  // default: true,
  // set to false to exclude all models, 
  // where `exportState` is undefined  
  filterDefault: false,
  
  // context will be passed to exportState callbacks
  context: {
    isLocalStorageExport: true,
  },

})

Models may include an exportState option, which must be either a function or a boolean.

export default {
  name: 'UserModel',
  exportState(context) {
    return context.isLocalStorageExport
        // vm can be accessed from withing the callback 
        && this.isLoggedIn
  }
}
export default {
  name: 'SomeOtherModel'
  exportState: false,
}

Server Side Rendering

// entry-server.js
Object.defineProperty(context, 'vueModelState', {
  get: () => {
    return app.$modelRegistry.exportState()
  },
})
<!-- index.html -->
{{{ renderState({ contextKey: 'vueModelState', windowKey: '__VUE_STATES__' }) }}}
// main.js
import { Registry } from '@sum.cumo/vue-states'

export default async function createApp() {
  // ...
  
  const modelRegistry = new Registry()

  if (typeof window !== 'undefined' && window.__VUE_STATES__) {
    modelRegistry.importState(window.__VUE_STATES__)
  }

  const app = new Vue({
    // you only need to provide this option if you need to import an initial state
    // the registry will be automatically initialized otherwise
    modelRegistry,
    // ...
  })
}

Multi-Instances

When using models for non application-wide state you might have multiple instances of the same model running concurrently. For import/export to work you will need to provide an id to further identify the different models.

export default modelId => ({
    // the combination of name and modelId must be unique at any given time 
    modelId, 

    data() {
      return {
        counter: 0,
      }
    },
    
    methods: {
      increment() {
        this.counter += 1
      },
    },
})
import createCounter from '@/models/counter'

export default {
  props: {
    someIdentifier: {
      type: String,
      required: true,
    }
  },
  
  // you may also pass a function that is evaluated in the created hook 
  // and receives the hosting Vue component as context
  models() {
    return {
      Counter: createCounter(this.someIdentifier),
    }
  }
}

Nuxt.js

Nuxt.js gets confused by the models attached to the component tree. The errors can be resolved by adding abtract: true to all models (which however makes them invisible in the developer tools).

Vue.use(
  VueStates, 
  { mixins: [ { abstract: true } ] }
)

License

Copyright 2019 sum.cumo GmbH

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


Learn more about sum.cumo and work on open source projects, too!