reqwq
v0.4.0
Published
A reactivity state manager of React.js
Maintainers
Readme
reqwq
test

A reactivity state manager of React.js
Install
npm install reqwqFeatures
- 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 AppAsync 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 AppCounterStore.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 FManually 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-polyfillThen import them:
import 'proxy-polyfill'
import { newInstance } from 'reqwq'Author
Shirasawa
