├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── example ├── index.html ├── main.js └── webpack.config.js ├── package.json ├── src ├── ActionsObservable.js └── index.js └── test ├── jasmine.json └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist 3 | node_modules 4 | example/bundle.js 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Evan You 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS REPOSITORY IS DEPRECATED 2 | 3 | ## vuex-observable 4 | 5 | > Proof of Concept, DO NOT USE YET 6 | 7 | Consume Vuex actions as Observables using RxJS 5, inspired by [redux-observable](https://github.com/redux-observable/redux-observable). 8 | 9 | ## Usage 10 | 11 | ``` js 12 | import Vue from 'vue' 13 | import Vuex from 'vuex' 14 | import { observableAction } from 'vuex-observable' 15 | import 'rxjs/add/operator/delay' 16 | 17 | Vue.use(Vuex) 18 | 19 | const store = new Vuex.Store({ 20 | state: { 21 | pinging: false 22 | }, 23 | mutations: { 24 | ping: state => state.pinging = true, 25 | pong: state => state.pinging = false 26 | }, 27 | actions: { 28 | ping: observableAction((action$, { commit }) => { 29 | action$.subscribe(() => commit('ping')) 30 | action$.delay(1000).subscribe(() => commit('pong')) 31 | }) 32 | } 33 | }) 34 | ``` 35 | 36 | ## TODOs 37 | 38 | - Working with multiple actions as source 39 | - Adaptors 40 | - Cancellation 41 | - HMR support 42 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vuex observable example 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /example/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import { observableAction } from '../src' 4 | import 'rxjs/add/operator/delay' 5 | 6 | Vue.use(Vuex) 7 | 8 | const store = new Vuex.Store({ 9 | state: { 10 | pinging: false 11 | }, 12 | mutations: { 13 | ping: state => state.pinging = true, 14 | pong: state => state.pinging = false 15 | }, 16 | actions: { 17 | // convert an action into an observableAction 18 | ping: observableAction((action$, { commit }) => { 19 | // first argument will be an observable representing 20 | // the stream for "ping" actions 21 | action$.subscribe(() => commit('ping')) 22 | action$.delay(1000).subscribe(() => commit('pong')) 23 | }) 24 | } 25 | }) 26 | 27 | new Vue({ 28 | store, 29 | el: '#app', 30 | template: ` 31 |
32 |

{{ $store.state.pinging }}

33 | 34 |
35 | ` 36 | }) 37 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | entry: path.resolve(__dirname, 'main.js'), 5 | output: { 6 | path: __dirname, 7 | filename: 'bundle.js' 8 | }, 9 | resolve: { 10 | alias: { 11 | vue$: 'vue/dist/vue.common.js' 12 | } 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.js$/, 18 | loader: 'babel-loader', 19 | exclude: /node_modules/ 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuex-observable", 3 | "version": "1.0.0", 4 | "description": "Use Observables in Vuex actions.", 5 | "main": "dist/index.js", 6 | "files": [ 7 | "dist" 8 | ], 9 | "scripts": { 10 | "dev": "webpack --config example/webpack.config.js -w -d", 11 | "build": "babel src -d dist", 12 | "test": "jasmine JASMINE_CONFIG_PATH=test/jasmine.json" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/vuejs/vuex-observable.git" 17 | }, 18 | "keywords": [ 19 | "vue", 20 | "vuex", 21 | "observable", 22 | "rx", 23 | "rxjs" 24 | ], 25 | "author": "Evan You", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/vuejs/vuex-observable/issues" 29 | }, 30 | "homepage": "https://github.com/vuejs/vuex-observable#readme", 31 | "peerDependencies": { 32 | "rxjs": "^5.0.0" 33 | }, 34 | "devDependencies": { 35 | "babel-core": "^6.18.2", 36 | "babel-loader": "^6.2.8", 37 | "babel-preset-es2015": "^6.18.0", 38 | "jasmine": "^2.5.2", 39 | "rxjs": "^5.0.0-rc.4", 40 | "vue": "^2.1.3", 41 | "vuex": "^2.0.0", 42 | "webpack": "^2.1.0-beta.27" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/ActionsObservable.js: -------------------------------------------------------------------------------- 1 | // borrowed from redux-observable (MIT Licensed) 2 | 3 | import { Observable } from 'rxjs/Observable' 4 | import { of } from 'rxjs/observable/of' 5 | import { from } from 'rxjs/observable/from' 6 | import { filter } from 'rxjs/operator/filter' 7 | 8 | export class ActionsObservable extends Observable { 9 | static of (...actions) { 10 | return new this(of(...actions)) 11 | } 12 | 13 | static from (actions, scheduler) { 14 | return new this(from(actions, scheduler)) 15 | } 16 | 17 | constructor (actionsSubject) { 18 | super() 19 | this.source = actionsSubject 20 | } 21 | 22 | lift (operator) { 23 | const observable = new ActionsObservable(this) 24 | observable.operator = operator 25 | return observable 26 | } 27 | 28 | ofType (...keys) { 29 | return filter.call(this, ({ type }) => { 30 | const len = keys.length 31 | if (len === 1) { 32 | return type === keys[0] 33 | } else { 34 | for (let i = 0; i < len; i++) { 35 | if (keys[i] === type) { 36 | return true 37 | } 38 | } 39 | } 40 | return false 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { Subject } from 'rxjs/Subject' 2 | import { ActionsObservable } from './ActionsObservable' 3 | 4 | export function observableAction (init) { 5 | const input$ = new Subject() 6 | const action$ = new ActionsObservable(input$) 7 | 8 | let $output 9 | return function observableAction (context, payload) { 10 | if (!$output) { 11 | $output = init(action$, context) 12 | } 13 | input$.next(payload) 14 | return $output 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "test", 3 | "spec_files": ["test.js"], 4 | "helpers": [ 5 | "../node_modules/babel-register/lib/node.js" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import { observableAction } from '../src' 4 | import 'rxjs/add/operator/delay' 5 | 6 | Vue.use(Vuex) 7 | 8 | describe('vuex-observable', () => { 9 | it('should work', done => { 10 | const store = new Vuex.Store({ 11 | state: { 12 | pinging: false 13 | }, 14 | mutations: { 15 | ping: state => state.pinging = true, 16 | pong: state => state.pinging = false 17 | }, 18 | actions: { 19 | ping: observableAction((action$, { commit }) => { 20 | action$.subscribe(() => commit('ping')) 21 | action$.delay(100).subscribe(() => commit('pong')) 22 | }) 23 | } 24 | }) 25 | 26 | store.dispatch('ping') 27 | expect(store.state.pinging).toBe(true) 28 | 29 | setTimeout(() => { 30 | expect(store.state.pinging).toBe(false) 31 | done() 32 | }, 100) 33 | }) 34 | }) 35 | --------------------------------------------------------------------------------