Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/toyobayashi/reactivuety

Use vue composition API with react
https://github.com/toyobayashi/reactivuety

Last synced: 28 days ago
JSON representation

Use vue composition API with react

Awesome Lists containing this project

README

        

# reactivuety

Write react in vue way.

[API Documentation](https://github.com/toyobayashi/reactivuety/blob/main/docs/api/index.md)

[中文](https://github.com/toyobayashi/reactivuety/blob/main/README_CN.md)

## Install

```
npm install @tybys/reactivuety
```

or

```html

```

## Compare with Vue

Markdown example:

Vue:

```vue




import { ref, computed, defineComponent } from 'vue'
import * as marked from 'marked'
import * as debounce from 'lodash/debounce'

export default defineComponent({
setup () {
const input = ref('# hello')
const compiledMarkdown = computed(() => marked(input.value))

const update = debounce(function(e) {
input.value = e.target.value;
}, 300)

return { input, compiledMarkdown, update }
}
})

```

Use `defineComponent`, the first argument is setup function, which returns a react renden function.

```jsx
// import ...
import * as React from 'react'
import { defineComponent, ref, computed, Textarea } from '@tybys/reactivuety'

export default defineComponent((vueProps) => {
const input = ref('# hello')
const compiledMarkdown = computed(() => ({ __html: marked(input.value) }))

const update = debounce((e) => {
input.value = e.target.value
}, 300)

return (reactProps, ref) => ( // <-- returns a react renden function
// use other react hooks here





)
})
```

No bundler:

```html

(function () {
var defineComponent = reactivuety.defineComponent;
var ref = reactivuety.ref;
var computed = reactivuety.computed;
var Textarea = reactivuety.Textarea;
var h = React.createElement;
var debounce = _.debounce;

var MarkdownView = defineComponent(function (vueProps) {
var input = ref('# hello');

var compiledMarkdown = computed(function () {
return { __html: marked(input.value) };
});

var update = debounce(function (e) {
input.value = e.target.value;
}, 300);

return function (reactProps, ref) {
// use other react hooks here
return h('div', { id: 'editor' },
h(Textarea, { value: input.value, onInput: update }),
h('div', { dangerouslySetInnerHTML: compiledMarkdown.value })
);
};
});
ReactDOM.render(h(MarkdownView), document.body);
})();

```

Use `defineComponent`, the first argument is setup function, which returns an object contains vue reactive objects, the second argument is a react function component render function whose with first argument is the object returned by the setup function.

```jsx
// import ...
export default defineComponent((vueProps) => {
const input = ref('# hello')
const compiledMarkdown = computed(() => ({ __html: marked(input.value) }))

const update = debounce((e) => {
input.value = e.target.value
}, 300)

return { input, compiledMarkdown, update }
}, (state, reactProps, ref) => (
// use other react hooks here





))
```

Use `useSetup` hook, the first argument is setup function, which returns an object contains vue reactive objects, the second argument is react props.

```jsx
// import ...
import * as React from 'react'
import { useSetup, ref, computed, Textarea } from '@tybys/reactivuety'

export default (reactProps) => {
const state = useSetup(
(vueProps) => {
const input = ref('# hello')
const compiledMarkdown = computed(() => ({ __html: marked(input.value) }))

const update = debounce((e) => {
input.value = e.target.value
}, 300)

return { input, compiledMarkdown, update }
},
reactProps // <-- pass react props
)

// use other react hooks here

return (





)
}
```

Use `useSetup` hook, the first argument is setup function, which returns a render function, the second argument is react props.

```jsx
// import ...
export default (reactProps, refOrContext) => {
const render = useSetup(
(vueProps) => {
const input = ref('# hello')
const compiledMarkdown = computed(() => ({ __html: marked(input.value) }))

const update = debounce((e) => {
input.value = e.target.value
}, 300)

return (reactProps, refOrContext) => (
// use other react hooks here





)
},
reactProps
)

return render(reactProps, refOrContext)
}
```

## Other usage

### nextTick

Similar to vue 3.

``` jsx
import { nextTick, ref, defineComponent } from '@tybys/reactivuety'
export default defineComponent(() => {
const a = ref('a')
const onClick = () => {
a.value = 'b'
console.log(document.getElementById('a').innerHTML) // a
nextTick(() => {
console.log(document.getElementById('a').innerHTML) // b
})
}

return () => (

{a.value}
)
})
```

### Lifecycles

Similar to vue 3.

``` jsx
import {
onBeforeMount,
onBeforeUnmount,
onBeforeUpdate,
onErrorCaptured,
onMounted,
onRenderTracked,
onRenderTriggered,
onUnmounted,
onUpdated,
defineComponent
} from '@tybys/reactivuety'

export default defineComponent(() => {
onBeforeMount(() => {})
onBeforeUnmount(() => {})
onBeforeUpdate(() => {})
onErrorCaptured((err, type) => {}) // <-- No instance
onMounted(() => {})
onRenderTracked((e) => {})
onRenderTriggered((e) => {})
onUnmounted(() => {})
onUpdated(() => {})
// ...
})
```

### Async component

Similar to vue 3. But no `suspensible` option.

```jsx
import { defineAsyncComponent } from '@tybys/reactivuety'

const MyComponent = defineAsyncComponent(() => import('./MyComponent'))

const MyComponent2 = defineAsyncComponent({
loader: () => import('./MyComponent'),
delay: 200,
loadingComponent: () => (),
errorComponent: ({ error }) => (

{error?.message}
),
timeout: Infinity
onError: (error, retry, fail) => {}
})
```

### Provide / Inject

Similar to vue 3.

In parent:

```jsx
import { provide, ref, defineComponent } from '@tybys/reactivuety'
export default defineComponent(() => {
const a = ref('')
provide('a', a)
// ...
})
```

In children (can be deep):

```jsx
import { inject, defineComponent } from '@tybys/reactivuety'
export default defineComponent(() => {
const a = inject('a')
// ...
})
```

### vModel

Similar to vue 3.

Support `` / `` / `` / ``

```jsx
import { defineComponent, ref, Input } from '@tybys/reactivuety'

export default defineComponent(() => {
const inputValue = ref('')

return () => () // <-- pass ref
/*
be equivalent to
return () => ( { inputValue.value = e.target.value }}
/>)
*/
})
```

Also support modifiers: `vModel_lazy` / `vModel_number` / `vModel_trim`

```jsx
import { defineComponent, ref, Input } from '@tybys/reactivuety'

export default defineComponent(() => {
const inputValue = ref('')

return () => ()
/* return () => (
{ inputValue.value = e.target.value }}
/>
)
})
```

### react compatible ref

```jsx
import { ref, onMounted, defineComponent } from '@tybys/reactivuety'
export default defineComponent(() => {
const a = ref(null)
onMounted(() => {
console.log(a.current) //

reactivuety

})

return () => (

reactivuety
)
})
```

## Note

* setup function is only called once, the first argument is readonly props `Proxy`

* setup function can return:

* object contains vue reactive object, all of them will be observed if accessed.

* render function without props, all accessed reactive objects in the render function will be observed.

* lifecycle hooks should be called in setup function.

* `inject()` should be called in setup function.

* if `provide()` is called outside of setup function, it will provide your variable to root.

* the `onChange` event of `` and `` is native, not react's.