vuejs / composition-api Goto Github PK
View Code? Open in Web Editor NEWComposition API plugin for Vue 2
Home Page: https://composition-api.vuejs.org/
License: MIT License
Composition API plugin for Vue 2
Home Page: https://composition-api.vuejs.org/
License: MIT License
In Vue 2.x we can use this.$store and this.$router, inside setup, we should use context.store or something? The only way I could use it is import the store in every SFC, but I prefer have global access, like in Vue 2.x if it's possible... thanks!
from Vue 2.x , when use with TypeScript we always write shims file d.ts
whichs support static type property used inside vue component object.
ex: in Nuxt, each component use as page
need defined $options.layout = 'layout name'
like this:
{
name: 'page',
layout: 'myLayout'
}
To typesafe this custom property, they provide d.ts
:
// ComponentOptions is declared in types/options.d.ts
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
layout?: string
}
}
For now vue-function-api
provide function createComponent
to help TS's developer can inherit typesafe from package. View d.ts
file i see function defined:
export declare function createComponent<PropsOptions, RawBindings>(options: ComponentOptions<PropsOptions, RawBindings>): VueProxy<PropsOptions, RawBindings>;
export interface ComponentOptions<PropsOptions = ComponentPropsOptions, RawBindings = Data, Props = ExtractPropTypes<PropsOptions>> {
props?: PropsOptions;
setup?: SetupFunction<Props, RawBindings>;
}
This not inherit from Vue ComponentOptions , so we lost all typesafe from shims file.
A modify d.ts code will help a lot to inherit from Vue 2.x setup env .
Thankyou!
context.slots
should hold functions like Vue 3.0 describes.
Context supplied to setup only contains slots and this.$scopedSlots doesn't work inside setup.
Is there an official way to access scoped slots?
Typescript need declare Context interface as param type when using setup method, can export it?
I am trying to create a hook:
import { value, computed, watch, onMounted } from 'vue-function-api';
export function useIntersectionObserver() {
let intersectionObserver;
const entry = value({});
const callback = (entries) => {
if (entries.length > 0) {
entry.value = entries[entries.length - 1];
}
};
onMounted(() => {
intersectionObserver = new IntersectionObserver(callback);
...
});
onUnmounted(() => {
intersectionObserver.disconnect();
});
return {
isIntersecting: computed(() => entry.isIntersecting)
};
}
And use that in some component:
import { value, computed, watch, onMounted } from 'vue-function-api';
import useIntersectionObserver from '...';
export default {
setup() {
useIntersectionObserver();
}
}
Yet, I get the error:
[vue-function-api] "onMounted" get called outside of "setup()"
Why is that, and how can I prevent this?
Hey! There is some way to use component methods, when you get it from refs?. Example:
// Input component
export default createComponent({
setup() {
function validate() { awesome validation }
return { validate };
}
})
// in some components with inputs
export default createComponent({
setup(props, vm) {
function create() {
// This refs hasn't my validate method
vm.refs.myCustomInputComponent.validate();
}
return { create };
}
})
The createElement
function has been added to the v2.2.0 release, which is great! 🎉
But the babel-sugar-inject-h
plugin attempts to automatically inject h
from this.$createElement
, but there is no this
in setup()
, so JSX cannot be used directly.
I tried to use the the onErrorCaptured
hook just as I used it in 2.x: code in CodeSandbox , outputs are in console.
The result is not in line with my expectation. Actually, the error was not captured, and because I usedVue.config.warnHandler
, I found that the error was treated as a warn, onErrorCaptured
was not called. But if I used it as 2.x, using errorCaptured
hook, it works properly. Did I get something wrong? Thanks.
And sorry for my poor English.
There is no life cycle method serverPrefetch
, so can not be fully used on SSR.
In order to support SSR, the only choice is to remain serverPrefetch()
method. And then, all methods and data properties used by serverPrefetch()
has to be remained. And then, very little code can be ported into setup()
method. And the code is in "mixed style", very ugly.
I am using a library X that uses [email protected]
and my own app uses [email protected]
this creates 2 separate vue-function-api
.
one in node_modules/vue-function-api
(v2.1.2)
and another one in node_modules/X/node_modules/vue-function-api
(v2.1.1)
I noticed vue-function-api
uses a variable that is scoped within the package, when library X uses inject
or provide
, and you use it in your app, it will error out.
e.g.
// library X using [email protected]
export function useX() {
const provider = inject<XProvider>(X_PROVIDER_KEY);
if (!provider) {
throw new Error('Unable to find provider');
}
return provider.value;
}
// app that uses [email protected]
export default Vue.extend({
setup(props, context) {
useX() // error, inject is called outside of setup
}
});
It has been 3 days after I commented in #62.
In my option, there should fewer breaking change. We should not start a breaking change as long as we can solve it, not open as much changes as we can. For examaple the name and components options , will probably inherited from vue 2, while now this package force us to hack it.
I really you should consider it carefully. Some users like me couldn't afford hacking and rehacking again and again while releasing new version.
Hi team!
i am using vue-function-api as proxy to make project in Vue2 with Vue3 api style. Today i found issue with provide
/ inject
:
first please see this code snippet :
provide / inject failed jsfiddle demo
step:
Vue.use(VeeValidate, { inject: false })
.Please see that in vee-validate plugin they allow disable auto-inject feature with option inject: false
. But i dont know why provide()
result replaced by other plugin, and dont know what vee-validate
did underground.
other attention is: if use Vue2.x provide style :
{
provide: {
T: { ok: true }
}
}
then we can inject use inject()
at any child component no issue!
When setup() return some plain props like this:
const Test = Vue.extend({
render(h) {
return h('div', [
h('span', this.count),
h('button', {
on: {
click: () => this.count++,
},
}, 'Increment'),
]);
},
setup() {
return { count: 0 };
},
});
count is not reactive but is attached to vm, so that it becomes a "immutable" state? Anyway, it might confuse the user.
Consider following implemention in src/setup.ts at line 58:
Object.keys(binding).forEach(name => {
let bindingValue = binding[name];
if (!isWrapper(bindingValue)) {
bindingValue = value(bindingValue);
}
bindingValue.setVmProperty(vm, name);
});
import { createComponent } from 'vue-function-api'
const MyComponent = createComponent({
props: {
msg: String
},
setup(props) {
console.log(props.msg == '1'); // string | undefined
// Error:(13, 25) TS2367: This condition will always return 'false' since the types 'StringConstructor' and '"1"' have no overlap.
}
})
Here is the declaration file:
import { AnyObject } from '../types/basic';
import { Wrapper } from '../wrappers';
export interface Key<T> extends Symbol {
}
export declare function provide(data: AnyObject): void;
export declare function provide<T>(key: Key<T>, value: T | Wrapper<T>): void;
export declare function inject<T>(key: Key<T>): Wrapper<T> | void;
But the doc says:
▸ provide(key: string | symbol, value: any)
▸ inject(key: string | symbol)
Equivalent with provide and inject from 2.x
So when I use string instead of exporting and importing symbols accross file, I got type error.
if use context.root will get the root vm of entire page, can i access current vm in setup function? i need to get the $route or $store of current vm instead of root vm.
We are new in vue and we want start a new project in next three months. Well we want to make sure that we are choosing the best environment which will be compatible with Vue future development path. And we want to be Vue3 compatible (as much as possible).
According to this plugin and a complete description at related rfc , the next VueJs movement will be toward function API and the Class API RFC is moved a way.
So using Typescript in a vue project ( for example sample mentioned at https://sobolevn.me/2019/06/really-typing-vue ) will not be a good idea.
Am I correct ?
Is it recommended to use function api and typescript together? And is there any sample which can help to get start.
PS: I have read this comment some where (Vue@3 will have improved typescript support), is it still correct?!
setup (props, context) cannot work with i18n Single File Compoents, because root.$t is defined but can't find the string key.
Works in template and works with global en.json
file.
This is more a clarification on how would one (or should one?) access what's now presented as the this.$el
HTML root template element.
Have I missed it in the RFC?
My workaround is to manually add an ref="el"
to the root template element and use context.refs.el
in, say, the onMounted
callback.
Excuse me, I can't find how call plugin in new Vue API.
import myPlugin from './myPlugin';
Vue.use(myPlugin);
const myPlugin = {
install(Vue) {
Vue.prototype.$test = 'test string';
}
}
export default myPlugin;
<script>
export default {
name: 'test',
setup(props, vm) {
console.log(vm.$test); //??
}
}
</script>
<script>
export default {
props: {
themeName: String
},
computed: {
$theme () {
return this[this.themeName]
}
}
}
</script>
<style module="$a">
.wrapper {
background: #000;
}
</style>
<style module="$b">
.wrapper {
background: #fff;
}
</style>
setup (props, context)
cannot work with CSS Modules, because context
does not has property $a
or $b
.
I've been playing with the new API the past couple days and really enjoy it. Thank you for all the work.
I may have missed it, or there is an alternate method to access the local component from within the setup function, but I have not been able to determine it.
From the RFC, it makes sense:
setup() {
function onClick() {
this // not the `this` you'd expect!
}
}
The request is to either make it more clear how to access the local component for less astute people such as myself or add the functionality. Or perhaps help me understand why I wouldn't want to. An example.
How to extend the context with own attrs? I use the Quasar framework with TypeScript and I can extends Vue instance with prototype inheritance.
export default async ({ Vue }) => {
Vue.prototype.$axios = axios
}
declare module 'vue/types/vue' {
interface Vue {
$axios: AxiosStatic;
}
}
Unfortunately, context.root
contains Vue
instance but it does not contain any prototyped extensions. :(
As a follow-up to liximomo/vue-function-api#10 (comment), the refs are now injected, but they can only be accessed inside of a lifecycle method. I don't believe this is the desired usage.
For example, I have a custom hook that binds and removes an event listener to the DOM node passed into it as a parameter. Because my custom hook cannot be called inside of a lifecycle method (because it has lifecycle methods inside of it), I can only call my custom hook at the first level of setup(). I like this functionality, and the errors were clear.
console.log("outside:");
console.log(context.refs.elementKeypress); // undefined
onMounted(() => {
console.log("inside:");
console.log(context.refs.elementKeypress); // <div data-v-763db97b="" class="element-keypress-demo">Ref</div>
});
// hook fails to bind event listener to 'undefined'
useElementKeypress("u", context.refs.elementKeypress, () => {
console.log("clicked!");
});
My problem is that the ref is undefined
when passing it into the custom hook.
Type Inference was a major motivation behind the Function-API. Surprisingly, I can't seem to find examples or even mentions to Typescript support in the README.md. Only the Function-API RFC seems to cover Typescript support.
This sandbox reproduces the error I get in App.tsx
https://codesandbox.io/s/vue-function-api-typescript-issue-vrycw
For some reason the sandbox fails to import the components, but the code actually works when opened in vscode.
The code actually works without issue, it's just that typescript complains that JSX element type 'HelloWorld' does not have any construct or call signatures.
when using a component declared with createComponent and a render function
create demo with cli, add code into App.vue
import { watch } from 'vue-function-api'
export default {
watch: {
$route: {
handler: function (val, oldVal) {
console.log('oldWatch: ', val)
},
immediate: true
}
},
setup (props, ctx) {
const { $route } = ctx.root
watch(() => $route, (val, oldVal) => {
console.log('newWatch: ', val)
})
}
}
上方的 Test.vue 是 问题用例
下方的 vue-function-api.js :是自己 对于 value 和 state 的实现方式。 可以解决
希望能给作者提供思路
const route = ctx.root.$route;
const parentDeptID = computed(() => route.params.id);
watch(parentDeptID, () => {
console.log(parentDeptID.value);
});
路由更改时候却没有执行console
I met a problems here. And here is my solution. I wonder if there is any other solution which is better?
props:{
src: { type: String, required: true }
},
setup(props){
onMounted(() => {
const img = new Image(); // Create new Image instance
img.src = props.src as unknown as string;
...
});
}
Hey gays, I am learning the source code.
and i see the setCurrentVM
uesd in setup.ts
like:
...
let preVm = getCurrentVM();
setCurrentVM(vm);
try {
binding = setup(props, ctx);
} catch (err) {
logError(err, vm, 'setup()');
} finally {
setCurrentVM(preVm);
}
...
I not sure why here need to set the vm
before call setup
and reset the vm
in finally section .
Can anyone help me to understand waht this is doing?
thx.
How to make unit test using jest / mocha with typescript?
@vue/test-utils/shallowMount(component) => wrapper.vm.*
does not contain type definitions which are returned from component so I cannot access anything even if returned data from setup exists in the browser when logging component to console.
Could someone provide an example please?
For example how to test returned values from setup?
export default {
setup(){
return { testThis: true };
}
}
version: 2.2.0
<script lang="ts">
import { createComponent } from "vue-function-api";
interface Props {
msg: string;
}
export default createComponent({
props: ({
msg: {
required: true,
}
} as unknown) as Props,
setup(props) {
return {
msg: props.msg
};
}
});
</script>
Reproduction
https://codesandbox.io/s/vue-template-xt1wt?fontsize=14
I've been testing out this new API, and found that provide()
can be called only once per component. If there are more than one call to provide()
(whether in setup()
or hook functions), the latest provide()
call seems to override all changes made by previous provide()
calls. I believe this should be fixed.
To test this out, you can take a look at App.vue
inside my code sandbox. If you uncomment the second provide()
line, the app will spit out injection error.
When using the plugin I get this error
[vue-function-api] "setup" must return a "Object", get "Function"
But the RFC says you can return a function from setup for manual renders https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md#usage-with-manual-render-functions
like this
import { value, createElement as h } from 'vue'
const MyComponent = {
setup(initialProps) {
const count = value(0)
const increment = () => { count.value++ }
return (props, slots, attrs, vnode) => (
h('button', {
onClick: increment
}, count.value)
)
}
}
vue-function-api
currently lacks support for vue-router in-component navigation guards (beforeRouteEnter
, beforeRouteUpdate
, and beforeRouteLeave
). Any plans to implement them in the near future, or it's out of scope of this project?
使用vuex只能一个个的computed吗,能不能像vue2中的mapState那样直接展开
Wouldn't it make more sense to move this package to @vue/function-api
to keep in line with the other official Vue packages?
After I updated to 2.2.0, I found that when I run npm run serve
, the develop server console ouput is just like this:
And I cannot run npm run build
, the process will crash because of the error.
However, the browser console didn't show any errors, and it can run normally. So I cannot simply reproduce it online... In fact, I just create the project with vue-cli3, and change App.vue
to this:
<script lang="ts">
import {createComponent} from 'vue-function-api';
import HelloWorld from './components/HelloWorld.vue';
export default createComponent({
components: {HelloWorld}
});
</script>
I read the RFC again, and maybe 3.x will continue to be compatible with the 2.x components option?
And when I went back to 2.1.2, the type error disappeared. Did I go something wrong? Or how can I import and use *.vue
components correctly?
<script lang="ts">
import { createComponent, value, Wrapper } from "vue-function-api";
export default createComponent({
setup(props, context) {
const tabs: Wrapper<string[]> = value(["tab2"]);
tabs.value.push("tab3"); // ['tab2', 'tab3']
// should ['tab1', 'tab2', 'tab3'] but ['tab2', 'tab2', 'tab3']
tabs.value.unshift("tab1");
// worked correctly
const tabs2: string[] = ["tab2"];
tabs2.push("tab3");
// ['tab1', 'tab2', 'tab3']
tabs2.unshift("tab1");
return {
tabs,
tabs2
};
}
});
</script>
by the way, version 2.0.6 worked fine
I have been relying on this for a significant part of a QA application I have been writing. Will this be available in some form or another in Vue 3? or should I begin rewriting things in .then()?
Thanks
The hook is not working properly
import {value, computed, watch, onMounted, onDestroyed, onCreated, state, createComponent} from 'vue-function-api';
import Vue from 'vue';
const MessageComponent = {
setup() {
const msg = value('hello');
onMounted(() => console.log('hello'));
return {
msg
};
}
};
export default createComponent({
setup() {
const Message = Vue.extend(MessageComponent);
const message = new Message();
onCreated(() => console.log('create message'));
return {};
}
});
Error: [vue-function-api] "onCreated" get called outside of "setup()"
"export 'filters' was not found in 'vue-function-api';
how use filters api in vue-function-api
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? 🙂
Thanks!
This specification.
https://github.com/vuejs/rfcs/blob/function-apis/active-rfcs/0000-function-api.md#typescript-only-props-typing
This component's props
will be an empty object.
<template>
<div> <!-- There is a div to prevent inheritance -->
<button :type="type" :disabled="disabled"><slot /></button>
</div>
</template>
<script lang="ts">
import { createComponent } from 'vue-function-api';
type Props = {
type?: 'button' | 'submit';
disabled?: boolean;
};
export default createComponent({
setup(props: Props) {
console.log(props); // Empty object {}
const { type = 'button', disabled = false } = props;
return {
type,
disabled,
};
},
});
</script>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.