vue-lens-mixin

1.0.0 • Public • Published

Vue Lens Mixin

Functional and fractal state management for Vue.js using lenses. (Proof of concept and probably not optimized for performance! Probably also not optimized for the best API)

  • Feels like local state, but is actually global state
  • Synchronization of state through out the component tree is automatic

Installation

npm install --save vue-lens-mixin

Usage

Your top-most component should have a state data containing the global state:

 <script>
   export default {
     name: 'App',
     data: function() {
       return {
+        state: {temperature: 80, wind: 42},
       };
     },
   };
 </script>

For every child component that needs a conversion layer from/to this global state, define the lens object {get, set} for the template.

 <script>
   export default {
     name: 'App',
     data: function() {
       return {
         state: {temperature: 80, wind: 42},

+        thermometerLens: {
+          get(state) {
+            const fahrenheit = state.temperature;
+            const celsius = Math.round(((fahrenheit - 32) * 5) / 9);
+            return celsius;
+          },
+
+          set(celsius, state) {
+            const fahrenheit = Math.round((celsius * 9) / 5 + 32);
+            return {...state, temperature: fahrenheit};
+          },
+        },
       };
     },
   };
 </script>

Notice that get and set is not the OOP style getters and setters, but instead its a pair of pure functions:

{
  get: parentState => childState,
  set: (newChild, oldParent?) => newParent
}

This lens should be passed on to child components using v-bind:lens=, for instance:

<template>
  <div id="app">
    <span>{{JSON.stringify(state)}}</span>
    <my-thermometer v-bind:lens="thermometerLens"/>
  </div>
</template>

To implement a component that expects a lens as prop, use the lens mixin. Notice also this component now expects its data to be under state:

import Vue from 'vue';
import * as lens from 'vue-lens-mixin';

Vue.component('my-thermometer', {
  mixins: [lens],
  template: `
    <div>
      <h1>European thermometer</h1>
      <button v-on:click="state -= 2">Colder</button>
      <button v-on:click="state += 2">Hotter</button>
      <h1>{{state}}°C</h1>
    </div>
  `,
});

This can be done for grandchildren components too. For instance, if my-thermometer has a child, just define a lens object in the my-thermometer, and render the child by passing the lens to it as props:

 import Vue from 'vue';
 import * as lens from 'vue-lens-mixin';

 Vue.component('my-thermometer', {
   mixins: [lens],
+  data: function () {
+    return {
+      childLens: {get: /* ... */, set: /* ... */}
+    }
+  },
   template: `
     <div>
       <h1>European thermometer</h1>
       <button v-on:click="state -= 2">Colder</button>
       <button v-on:click="state += 2">Hotter</button>
       <h1>{{state}}°C</h1>
+      <child-component v-bind:lens="childLens"/>
     </div>
   `,
 });

License

MIT

Readme

Keywords

Package Sidebar

Install

npm i vue-lens-mixin

Weekly Downloads

1

Version

1.0.0

License

MIT

Unpacked Size

5.18 kB

Total Files

4

Last publish

Collaborators

  • staltz