vuejs / composition-api

Composition API plugin for Vue 2
https://composition-api.vuejs.org/
MIT License
4.19k stars 343 forks source link

Can I use functional api with vuex? #18

Closed mspoulsen closed 5 years ago

mspoulsen commented 5 years ago

Hi,

I am really eager to try this new api and especially the typescript integration. But can I use this api with vuex? If so could anybody provide an example? :slightly_smiling_face:

Thanks!

a9 commented 5 years ago

see comment https://github.com/vuejs/vue-function-api/issues/8#issuecomment-506143686

SilentDepth commented 5 years ago

Actually, after splitting states into hooks, I removed vuex from my project dependencies. 🤪

u3u commented 5 years ago

Hi, everyone, I created a vue-hooks repository and package. It contains commonly used hooks (e.g: vuex / vue-router). Documentation has not been written yet, welcome everyone to contribute! 😄

gianko commented 5 years ago

@SilentDepth how are you sharing sharing vue-function-api state between components?

care to share an example? please

SilentDepth commented 5 years ago

@gianko Just like this:

/* hook-msg.js */

import {value as binding} from 'vue-function-api'

const msg = binding('hello world')

export default function useMsg () {
  return {
    msg,
  }
}
/* comp-a.vue */

import useMsg from './hook-msg'

export default {
  setup () {
    const {msg} = useMsg()

    return {
      msg,
    }
  },
}
/* comp-b.vue */

import {computed} from 'vue-function-api'
import useMsg from './hook-msg'

export default {
  setup () {
    const {msg} = useMsg()

    return {
      msgUpperCased: computed(() => msg.value.toUpperCase()),
    }
  },
}
gianko commented 5 years ago

Thanks!... I was getting an error about using vue function api before calling the use plugin.

thommath commented 5 years ago

I used the trick in the #8 answer but built on it a bit by making a small vuex plugin to do the wrapping of my getters.

Feels kind of hacky, but then all getters can be unpacked in one line

/* store-plugin.js */
import { computed } from 'vue-function-api'

let getters = {};

const myPlugin = store => {
  Object.keys(store.getters)
    .forEach(key => (getters[key] = computed(() => store.getters[key])));
}

export {
  myPlugin,
  getters
};

Then the computed getters can be accessed with:

/* some-vue-file.vue */
import { getters } from './store-plugin.vue';

const { someGetter, someOtherGetter } = getters;
furryablack commented 5 years ago

What do you think about https://github.com/zerobias/effector as a state manager?

Vue-function-api is the great thing with jsx =) I thinking vuex doesn't need anymore =D

See:

// @app/core/hooks/use-value
import { value } from "vue-function-api"

export const useValue = (initialValue, lazy) => {
  lazy = !!lazy
  const state = value(initialValue)
  const dispatch = (newValue) => {
    if (!lazy) {
      state.value = newValue
    } else if (state.value !== newValue) {
      state.value = newValue
    }
  }
  const reset = () => dispatch(initialValue)
  return [state, dispatch, reset]
}

// @app/core/hooks/use-reducer
import { useValue } from "./use-value"

export const useReducer = (reducer, initialValue, lazy) => {
  const [state, set, reset] = useValue(initialValue, lazy)
  const dispatch = (payload) => {
    const reducerResult = reducer(state.value, payload)
    set(reducerResult)
  }
  return [state, dispatch, reset]
}

Example:

import { useReducer } from "@app/core/hooks/use-reducer"

function reducer(value, payload) {
    switch (payload.type) {
      case "increment":
        return value + 1
      case "decrement":
        return value - 1
      default:
        throw new Error()
    }
}

export const ExampleCounter = {
  setup() {
    const initialValue = 0

    const [count, updateCount, reset] = useReducer(reducer, initialValue)

    const increment = () => updateCount({ type: "increment" })
    const decrement = () => updateCount({ type: "decrement" })

    // No needs, we have reset state function already
    // const reset = () => updateCount({ type: "reset" })

    return {
      count,
      increment,
      decrement,
      reset,
    }
  },

  render(h) {
    return (
      <div>
        Count: {this.counter.toString()}
        <button vOn:click_prevent={this.increment}>+</button>
        <button vOn:click_prevent={this.decrement}>-</button>
        <button vOn:click_prevent={this.reset}>reset</button>
      </div>
    )
  },
}

PS: Example uses jsx - vue requires the next babel plugins for that

{
  plugins: [
    "@vue/babel-plugin-transform-vue-jsx",
    "@vue/babel-sugar-v-on",
  ]
}
posva commented 5 years ago

Duplicate of #8

blowsie commented 4 years ago

@SilentDepth i presume this example is not still relevant? I tried to do the equivalent using ref and got an error Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function.

@gianko Just like this:

/* hook-msg.js */

import {value as binding} from 'vue-function-api'

const msg = binding('hello world')

export default function useMsg () {
  return {
    msg,
  }
}
/* comp-a.vue */

import useMsg from './hook-msg'

export default {
  setup () {
    const {msg} = useMsg()

    return {
      msg,
    }
  },
}
/* comp-b.vue */

import {computed} from 'vue-function-api'
import useMsg from './hook-msg'

export default {
  setup () {
    const {msg} = useMsg()

    return {
      msgUpperCased: computed(() => msg.value.toUpperCase()),
    }
  },
}
SilentDepth commented 4 years ago

@blowsie You need to call Vue.use() first, before any composition api being used.

The missing entry file of my example:

/* main.js */

import Vue from 'vue'
import './use-composition-api'
import App from './app.vue'

new Vue({
  render: h => h(App),
})
/* use-composition-api.js */

import Vue from 'vue'
import CompositionApi from '@vue/composition-api'

Vue.use(CompositionApi)