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

reqwq

v0.4.0

Published

A reactivity state manager of React.js

Downloads

14

Readme

reqwq JavaScript Style Guide npm test codecov GitHub stars

A reactivity state manager of React.js

简体中文 English

Install

npm install reqwq

Features

  • Reactivity: When you modify them, the view updates.
  • Lightweight: Only 2KB (gzip).
  • TypeScript Support: Includes TypeScript definitions.
  • Proxy: Build on ES6 Proxy.
  • Immutable: Data update does not modify the previous object.
  • Hooks Support: React hooks syntax supporting.

Usage

Create a store

CounterStore.ts:

import { Store } from 'reqwq'

export default class CounterStore extends Store {
  public count = 0
  public add () {
    this.count++
  }
}

Apply to your application

App.tsx:

import React from 'react'
import CounterStore from './CounterStore'
import { useStore, newInstance } from 'reqwq'

const Provider = newInstance(CounterStore)

const Counter: React.FC = () => {
  const store = useStore(CounterStore)
  return (
    <>
      <span>Count: {store.count}</span>
      <button onClick={store.add}>Add</button>
    </>
  )
}

const App: React.FC = () => (<Provider><Counter /></Provider>)
export default App

Async support

CounterStore.ts:

# import { Store } from 'reqwq'

+ const sleep = (time: number) => new Promise(resolve => setTimeout(resolve, time))
# export default class CounterStore extends Store {
#   public count = 0
+   public loading = false
-   public add () {
+   public async add () {
+     this.loading = true
+     await sleep(5000)
#     this.count++
+     this.loading = false
#   }
# }

App.tsx:

# const Counter: React.FC = () => {
#   const store = useStore(CounterStore)
#   return (
#     <>
#       <span>Count: {store.count}</span>
-       <button onClick={store.add}>Add</button>
+       <button onClick={store.add} disabled={store.loading}>Add</button>
#     </>
#   )
# }

Reference data from another Store

AnotherStore.ts:

import { Store } from 'reqwq'

export default class AnotherStore extends Store {
  public messages = ['hello']
  public world () { this.messages.push('world!') }
}

App.tsx:

# import React from 'react'
# import CounterStore from './CounterStore'
+ import AnotherStore from './AnotherStore'
# import { useStore } from 'reqwq'

- const Provider = newInstance(CounterStore)
+ const Provider = newInstance(CounterStore, AnotherStore)
+ const anotherStore = Provider.getStore(AnotherStore) // This is OK.

# const Counter: React.FC = () => {
#   const store = useStore(CounterStore)
+   const store2 = useStore(AnotherStore)
+   console.log(store2.messages)
#   return (
#     <>
#       <span>Count: {store.count}</span>
#       <button onClick={store.add}>Add</button>
#     </>
#   )
# }

# const App: React.FC = () => (<Provider><Counter /></Provider>)
# export default App

CounterStore.ts:

# import { Store, injectStore, getStore } from 'reqwq'
# import AnotherStore from './AnotherStore'

# export default class CounterStore extends Store {
+   @injectStore(AnotherStore)
+   private readonly anotherStore: AnotherStore
+
+   private readonly store2 = getStore(AnotherStore) // This is OK.
#   public count = 0
#   public add () {
#     this.count++
+     this.anotherStore.world()
+     this.store2.messages.forEach(alert)
+     // this.getStore(AnotherStore).messages // This is OK.
#   }
# }

Add stores dynamically

import { newInstance } from 'reqwq'
import CounterStore from './CounterStore'

const Provider = newInstance(CounterStore)

const fn = async () => {
  const AnotherStore = await import('./AnotherStore')
  Provider.addStores(AnotherStore)
}
fn()

Class Component

import React, { Component } from 'react'
import { withStores } from 'reqwq'
import CounterStore from './CounterStore'
import AnotherStore from './AnotherStore'

@withStores({ store1: CounterStore, store2: AnotherStore })
export class C extends Component {
  public render () {
    const { store1, store2 } = this.props
    return <>Count: {store1.count}</>
  }
}

@withStores({ counter: CounterStore }, (m, props) => ({ stores: m }))
export class D extends Component {
  public render () {
    const { stores } = this.props
    return <>Count: {stores.counter.count}</>
  }
}

Class Component with reactivity store

import React from 'react'
import { ComponentWithStore, PureComponentWithStore } from 'reqwq'

export default class C extends ComponentWithStore {
  private i = 0
  public render () {
    return <>
      <p>{this.i}</p>
      <button onClick={() => this.i++}>Add</button>
    </>
  }
}

Hooks with reactivity store

import React from 'react'
import { useOutsideStore } from 'reqwq'

class Store {
  public data = []
  public push () { this.data.push(Math.random()) }
}
const F: React.FC = () => {
  const store = useOutsideStore(() => new Store())
  return <>
    Array: {store.data.join(',')}
    <button onClick={store.push}>Push</button>
  </>
}
export default F

Manually patch data

By default, the data will be updated at the end of the event loop. If you want to update in advance, you need to do the following:

// Global store:
const G = newInstance(Store)
G.patch()

// Component with reactivity store:
class C extends ComponentWithStore {
  private i = 0
  public fn () { this.patch() }
}

// Hooks with reactivity store:
const store = useOutsideStore(() => new Store())
store.patch()

Babel plugin: react-model (rModel)

With this babel plugin, you can easily use two-way data binding likes Vue.js

.babelrc

{
  "plugin": ["reqwq/babel-plugin.js"]
}

Config

{
  "plugin": [["reqwq/babel-plugin.js"], { "prefix": "r", "notTransformObject": false }]
}

Usage

<input rModel={this.text} />
<input rModel={this.count} type="number" /> // this.count must be a number
<input rModel={this.checked} type="radio" /> // property name is 'checked'
<input rModel={this.checked} type="checkbox" /> // property name is 'checked'
<MyInput rModel={this.custom} rPropName="customProp" />
<MyCheckBox rModel={this.checked} rPropName="checked" />

Equivalent to:

<input value={this.text} onChange={a => {
  a = a.target.value
  this.text = typeof this.value === 'number' ? +a : a
}} />

IE 9 and Safari 6

Firstly, install module:

npm i proxy-polyfill

Then import them:

import 'proxy-polyfill'
import { newInstance } from 'reqwq'

Author

Shirasawa

License

MIT