npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tybys/reactivuety

v0.9.0

Published

Use vue composition API with react

Downloads

5

Readme

reactivuety

Write react in vue way.

API Documentation

中文

Install

npm install @tybys/reactivuety

or

<script src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tybys/reactivuety/dist/reactivuety.min.js"></script>

Compare with Vue

Markdown example:

Vue:

<template>
  <div id="editor">
    <textarea :value="input" @input="update"></textarea>
    <div v-html="compiledMarkdown"></div>
  </div>
</template>

<script>
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 }
  }
})
</script>

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

// 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
    <div id="editor">
      <Textarea value={input.value} onInput={update} />
      <div dangerouslySetInnerHTML={compiledMarkdown.value}></div>
    </div>
  )
})

No bundler:

<script src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/lib/marked.min.js"></script>

<script src="https://cdn.jsdelivr.net/npm/@tybys/reactivuety/dist/reactivuety.min.js"></script>
<script>
  (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);
  })();
</script>

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.

// 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
  <div id="editor">
    <Textarea value={state.input} onInput={state.update} />
    <div dangerouslySetInnerHTML={state.compiledMarkdown}></div>
  </div>
))

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

// 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 (
    <div id="editor">
      <Textarea value={state.input} onInput={state.update} />
      <div dangerouslySetInnerHTML={state.compiledMarkdown}></div>
    </div>
  )
}

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

// 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
        <div id="editor">
          <Textarea value={input.value} onInput={update} />
          <div dangerouslySetInnerHTML={compiledMarkdown.value}></div>
        </div>
      )
    },
    reactProps
  )

  return render(reactProps, refOrContext)
}

Other usage

nextTick

Similar to vue 3.

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 () => (<div id="a" onClick={onClick}>{a.value}</div>)
}) 

Lifecycles

Similar to vue 3.

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.

import { defineAsyncComponent } from '@tybys/reactivuety'

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

const MyComponent2 = defineAsyncComponent({
  loader: () => import('./MyComponent'),
  delay: 200,
  loadingComponent: () => (<MyLoading />),
  errorComponent: ({ error }) => (<div>{error?.message}</div>),
  timeout: Infinity
  onError: (error, retry, fail) => {}
})

Provide / Inject

Similar to vue 3.

In parent:

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

In children (can be deep):

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

vModel

Similar to vue 3.

Support <Input> / <Select> / <Option> / <Textarea>

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

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

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

Also support modifiers: vModel_lazy / vModel_number / vModel_trim

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

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

  return () => (<Input vModel_lazy={inputValue} />)
  /* return () => (
    <Input
      value={inputValue.value}
      onChange={(e) => { inputValue.value = e.target.value }}
    />
  )
})

react compatible ref

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

  return () => (<div ref={a}>reactivuety</div>)
})

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 <Input> and <Textarea> is native, not react's.