Skip to content

Commit

Permalink
feat: add suspendedProp and suspendable
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbonnet committed Feb 25, 2019
1 parent 3810f75 commit 3ff659b
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 63 deletions.
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ The `realue` module exposes the following functions:

- [Value-based decorators](#value-based-decorators)
- [`defaultValue`](#defaultvalue)
- [`initialValue`](#initialvalue)
- [`transformable`](#transformable)
- [`filterable`](#filterable)
- [`delayable`](#delayable)
- [`suspendable`](#suspendable)
- [`editable`](#editable)
- [`cyclable`](#cyclable)
- [`promised`](#promised)
Expand All @@ -90,6 +92,9 @@ The `realue` module exposes the following functions:
- [Decorator constructors](#decorator-constructors)
- [`withEffect()`](#witheffect)
- [`onPropsChange()`](#onpropschange)
- [`defaultProp()`](#defaultprop)
- [`initialProp()`](#initialprop)
- [`suspendedProp()`](#suspendedprop)
- [`delayedProp()`](#delayedprop)
- [`editableProp()`](#editableprop)
- [`syncedProp()`](#syncedprop)
Expand Down Expand Up @@ -149,7 +154,15 @@ The `realue` module exposes the following functions:

#### `defaultValue`

> ⬆️ `{ defaultValue, value }`
> ⬆️ `{ defaultValue?, value? }`
> ⬇️ `{ value? }`
Sets `value` to `defaultValue` if `value` is `nil`.

#### `initialValue`

> ⬆️ `{ initialValue?, value? }`
> ⬇️ `{ value? }`
Expand Down Expand Up @@ -182,6 +195,15 @@ Prevents `onChange` call if `filterOnChange(value, name, payload)` is set and re
Delays `onChange` calls until after `delay` milliseconds have elapsed since the last call.
Renames undelayed `onChange` as `onPush`.

#### `suspendable`

> ⬆️ `{ value, delay? }`
> ⬇️ `{ value? }`
Delays `onChange` calls until after `delay` milliseconds have elapsed since the last call.
Renames undelayed `onChange` as `onPush`.

#### `editable`

> ⬆️ `{ value, name, onChange, onPull(value, previousValue)? }`
Expand Down Expand Up @@ -297,6 +319,18 @@ Sets `[name]` to `[defaultName]` if `[name]` is `nil`.
Sets `[name]` to `[initialName]` on first render if `[initialName]` is not `nil`, then to `[name]` for subsequent renders.

#### `suspendedProp()`

> ➡️ `({ name, delayName?, onPullName? } | name)`
> ⬆️ `{ [name], [delayName] }`
> ⬇️ `{ [name], [onPullName] }`
Suspends `[name]` changes for `[delayName]` milliseconds. Subsequent `[name]` changes cancel previous suspensions.
Calling the injected method `[onPullName]` immediately sets `[name]` to the latest value.
If `[delayName]` is falsy, no suspension occurs, nor the injection of `[onPullName]`.

#### `delayedProp()`

> ➡️ `({ name, delayName?, onPushName?, mode? } | name)`
Expand All @@ -305,8 +339,9 @@ Sets `[name]` to `[initialName]` on first render if `[initialName]` is not `nil`
> ⬇️ `{ [name], [onPushName] }`
Delays `[name]` calls until after `[delayName]` milliseconds have elapsed since the last call if `options.mode` is `'debounce'` (default value), or calls `[name]` at most once every `[delayName]` milliseconds if `options.mode` is `'throttle'`.
Delays `[name]` calls until after `[delayName]` milliseconds have elapsed since the last call if `options.mode` is `'debounce'` (default value), or calls `[name]` at most once every `[delayName]` milliseconds if `options.mode` is `'throttle'`. The `mode` can also be a function that returns a callback based from the `([name], [delayName])` arguments.
Renames undelayed `[name]` as `['onPush' + name]`.
If `[delayName]` is falsy, no delay occurs nor the injection of `[onPushName]`.

#### `editableProp()`

Expand Down
77 changes: 50 additions & 27 deletions demo/client/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createElement as $ } from 'react'
import { createElement as $, Fragment } from 'react'
import { render } from 'react-dom'
import {
map,
Expand All @@ -12,6 +12,7 @@ import {
upperFirst,
reverse,
slice,
isEmpty,
} from 'lodash'
import {
compose,
Expand All @@ -36,7 +37,6 @@ import {
EMPTY_ARRAY,
filterable,
fromEvent,
logProps,
number,
object,
omitProps,
Expand All @@ -55,6 +55,9 @@ import {
withArrayChildren,
syncedProp,
withObjectChildren,
logProps,
initialValue,
suspendable,
} from '../../src'

import { request } from './requests'
Expand Down Expand Up @@ -618,6 +621,29 @@ const Request = compose(
const User = withProps({ type: 'user' })(Request)
const Device = withProps({ type: 'device' })(Request)

export const Progress = compose(
pure,
withProps(({ value, delay }) => ({
delay: value ? (delay / 2) | 0 : delay,
initialValue: true,
})),
initialValue,
suspendable,
)(function Progress({ value, error }) {
return $(
'p',
null,
!value
? 'Loading…'
: error
? [
'It looks like the API server is not running. Start it with: ',
$('code', null, 'npm run start:api'),
]
: ' ',
)
})

export const App = compose(
withProps({
request,
Expand All @@ -639,35 +665,32 @@ export const App = compose(
delayable,
editable,
object,
)(function App({ property, done, error }) {
)(function App({ value, property, done, error, delay }) {
return $(
'div',
null,
$('h1', null, 'Realue'),
$(
'p',
null,
!done
? 'Loading…'
: error
? [
'It looks like the API server is not running. Start it with: ',
$('code', null, 'npm run start:api'),
]
: 'Ready.',
),
$('h2', null, 'Timers'),
$(Timer, { value: Date.now() }),
$('h2', null, 'Todos'),
$(EditedItems, property('todos')),
$('h2', null, 'Color'),
$(Color, property('color')),
$('h2', null, 'Resources'),
$(Resources),
$('h2', null, 'Delayed'),
$(Toggle, { ...property('toggle'), delay: 2000 }),
$('h2', null, 'Children'),
$(Article, { value: { header: 'Title', body: 'Content' } }),
$(Progress, { value: done, error, delay }),
isEmpty(value)
? null
: $(
Fragment,
null,
$('h2', null, 'Delay'),
$(Number, { ...property('delay'), min: 0, max: 5000 }),
$('h2', null, 'Color'),
$(Color, property('color')),
$('h2', null, 'Timers'),
$(Timer, { value: Date.now() }),
$('h2', null, 'Todos'),
$(EditedItems, property('todos')),
$('h2', null, 'Resources'),
$(Resources),
$('h2', null, 'Delayed'),
$(Toggle, { ...property('toggle'), delay: 2000 }),
$('h2', null, 'Children'),
$(Article, { value: { header: 'Title', body: 'Content' } }),
),
)
})

Expand Down
9 changes: 7 additions & 2 deletions demo/server/middlewares.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Router from 'koa-router'
import lodash from 'lodash'

import { waitFor } from '../../src'

const {
map,
filter,
Expand All @@ -15,6 +17,7 @@ const {

const DATABASE = {
value: {
delay: 2000,
todos: [
{ done: false, label: 'eye' },
{ done: false, label: 'touch' },
Expand Down Expand Up @@ -46,10 +49,12 @@ const DATABASE = {
}

const router = new Router()
router.get('/value', (context, next) => {
router.get('/value', async (context, next) => {
await waitFor(DATABASE.value.delay)
context.response.body = JSON.stringify(DATABASE.value)
})
router.put('/value', (context, next) => {
router.put('/value', async (context, next) => {
await waitFor(DATABASE.value.delay)
const value = context.request.body
DATABASE.value = value
context.response.body = JSON.stringify(value)
Expand Down

0 comments on commit 3ff659b

Please sign in to comment.