Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

async-selector

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-selector - npm Package Compare versions

Comparing version 1.0.7 to 1.0.8

253

__tests__/index.test.js

@@ -357,3 +357,3 @@ import createAsyncSelector from '../src/index';

test('throttle', () => {
test('throttle', done => {
let c = 0;

@@ -375,5 +375,10 @@ const state = {text: 'Ma'};

setTimeout(() => {
employees(state);
employees({text: 'Marc'});
const result = employees(state);
expect(deepEqual(result, expected)).toBe(true);
try {
expect(deepEqual(result, expected)).toBe(true);
} catch (e) {
done.fail(e)
}
done()
},200)

@@ -383,3 +388,3 @@

test('throttle', () => {
test('throttle', done => {
let c = 0;

@@ -405,3 +410,9 @@ let state = {text: 'Ma'};

const result = employees(state);
expect(deepEqual(result, expected)).toBe(true);
try {
expect(deepEqual(result, expected)).toBe(true);
} catch (e) {
done.fail(e)
}
done()
}, 500);

@@ -411,3 +422,3 @@ },200)

test('throttle memoization', () => {
test('throttle memoization', done => {
let c = 0;

@@ -436,3 +447,8 @@ let state = {text: 'Ma'};

const result = employees(state);
expect(c).toBe(1);
try {
expect(c).toBe(1);
} catch (e) {
done.fail(e)
}
done();
}, 500);

@@ -444,2 +460,3 @@ },200)

function getAges(employees, maxAge) {
return new Promise((resolve, reject) => {

@@ -449,4 +466,4 @@ setTimeout(() => {

const ages = [12, 34];
if (text.length > 10) {
reject('Search Text Too Long');
if (maxAge < 3) {
reject('too young');
} else {

@@ -485,3 +502,3 @@ const employeeAges = employees.map(name => {

test('multiple params2', () => {
test('multiple params2', done => {
let c = 0;

@@ -493,3 +510,3 @@ let state = {employees: ['Mark Metzger'], maxAge: 40};

value: [12],
previous: undefined,
previous: [12],
isWaiting: false,

@@ -502,10 +519,13 @@ isResolved: true,

setTimeout(() => {
console.log(expected);
const result = ages(state);
console.log('blahhhhh', result);
expect(deepEqual(result, expected)).toBe(true);
try {
expect(deepEqual(result, expected)).toBe(true);
} catch (e) {
done.fail(e)
}
done();
}, 300);
});
test('multiple params3', () => {
test('multiple params3', done => {
let c = 0;

@@ -518,3 +538,3 @@ let state = {employees: ['Mark Metzger'], maxAge: 10};

value: [],
previous: undefined,
previous: [],
isWaiting: false,

@@ -528,5 +548,202 @@ isResolved: true,

const result = ages(state);
expect(deepEqual(result, expected)).toBe(true);
try {
expect(deepEqual(result, expected)).toBe(true);
} catch (e) {
done.fail(e)
}
done();
});
}, 200);
});
test('debounced memoized', done => {
let c = 0;
let state = {employees: ['Mark Metzger'], maxAge: 10};
const throttle = f => _.debounce(f, 100)
const onResolve = () => {c++}
const ages = createAsyncSelector(
{...params2, throttle, onResolve },
s => s.employees,
s => s.maxAge);
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
try {
expect(c).toBe(1);
} catch (e) {
done.fail(e)
}
done();
}, 122);
}, 122);
}, 122);
}, 120);
}, 120);
});
test('debounced memoized 2', done => {
let c = 0;
let state = {employees: ['Mark Metzger'], maxAge: 10};
const throttle = f => _.debounce(f, 100)
const onResolve = () => {c++}
const ages = createAsyncSelector(
{...params2, throttle, onResolve },
s => s.employees,
s => s.maxAge);
ages(state);
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
try {
expect(c).toBe(1);
} catch (e) {
done.fail(e)
}
done();
}, 122);
}, 122);
}, 122);
}, 120);
}, 120);
});
test('debounced memoized 3', done => {
let c = 0;
let state = {employees: ['Mark Metzger'], maxAge: 10};
const throttle = f => _.debounce(f, 100)
const onResolve = () => {c++}
const ages = createAsyncSelector(
{...params2, throttle, onResolve },
s => s.employees,
s => s.maxAge);
ages(state);
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages({employees: ['Mark Metzger'], maxAge: 9})
setTimeout(() => {
ages(state);
setTimeout(() => {
try {
expect(c).toBe(2);
} catch (e) {
done.fail(e)
}
done();
}, 88);
}, 188);
}, 88);
}, 80);
}, 180);
});
test('debounced memoized 4', done => {
let c = 0;
let state = {employees: ['Mark Metzger'], maxAge: 100};
const throttle = f => _.debounce(f, 100)
const onResolve = () => {c++}
const ages = createAsyncSelector(
{...params2, throttle, onResolve },
s => s.employees,
s => s.maxAge);
const expected = {
value: [],
previous: [],
isWaiting: false,
isResolved: true,
isRejected: false,
}
ages(state);
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
const n = {employees: ['Mark Metzger'], maxAge: 9};
ages(n);
setTimeout(() => {
ages(state);
setTimeout(() => {
const result = ages(n);
console.log(result);
try {
expect(deepEqual(expected, result)).toBe(true);
} catch (e) {
done.fail(e)
}
done();
}, 88);
}, 188);
}, 88);
}, 80);
}, 180);
});
test('debounced memoized 5', done => {
let c = 0;
let state = {employees: ['Mark Metzger'], maxAge: 10};
const throttle = f => _.debounce(f, 100)
const onResolve = () => {c++}
const ages = createAsyncSelector(
{...params2, throttle, onResolve },
s => s.employees,
s => s.maxAge);
const expected = {
value: [],
previous: [12],
isWaiting: true,
isResolved: false,
isRejected: false,
}
ages(state);
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
ages(state);
setTimeout(() => {
const n = {employees: ['Mark Metzger'], maxAge: 20};
ages(n);
setTimeout(() => {
ages(state);
setTimeout(() => {
const result = ages({employees: ['Mark Metzger'], maxAge: 20});
try {
expect(deepEqual(expected, result)).toBe(true);
} catch (e) {
done.fail(e)
}
done();
}, 88);
}, 188);
}, 88);
}, 80);
}, 180);
});

6

dist/index.js

@@ -87,4 +87,4 @@ 'use strict';

if (throttle !== null && f === null) {
f = throttle(function (state, forceUpdate) {
return func(state, forceUpdate, true);
f = throttle(function (state) {
return func(state, true, true);
});

@@ -94,3 +94,3 @@ }

f(state, forceUpdate);
memoizedResult = createResultObject(sync(mapped), previousResolution, true, false, false, omitStatus);
memoizedResult = createResultObject(sync.apply(undefined, _toConsumableArray(mapped)), previousResolution, true, false, false, omitStatus);
return memoizedResult;

@@ -97,0 +97,0 @@ }

{
"name": "async-selector",
"version": "1.0.7",
"version": "1.0.8",
"description": "Select values from databases using asynchronous selectors.",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -11,9 +11,9 @@ A simple, lightweight library inspired by [reselect](https://github.com/reduxjs/reselect) which allows you select data out of a remote database almost as easily as you would from local state. This library will normally be used in conjunction with redux and reselect but it has no dependencies.

### Problems
This way has many common problem that just about everybody has experienced
This way has many common problems that just about everybody has experienced.
- An old request could potential overwrite the data of a newer request if you don't handle that edge case.
- During the time between the request being sent and the response received, you might be rendering stale data.
- Having many variables in state and associated actions/reducers for the query status is a lot of redundant, tedious code
- Having many variables in state and associated actions/reducers for the query status is a lot of redundant, tedious code.
- If you have requests that depend on previous responses, this could result in callback hell and/or difficulty in reuse of the first response's data.
- There is no guarantee that multiple duplicate requests won't be made.
- Sending queries in response to user actions can result in brittle code and isn't really in the spirit of redux/reselect (Unless it's actually necessary)
- Sending queries in response to user actions can result in brittle code and isn't really in the spirit of redux/reselect (Unless it's actually necessary). For example, if you call a function in a server based on many user inputs, you will have to write code to send a query for every input field.

@@ -26,3 +26,3 @@ # Async selectors to the rescue!

```
```js
import createAsyncSelector from 'async-selector'

@@ -62,3 +62,3 @@ import { store } from './index' // get store somehow

```
```js
// Request in progress

@@ -76,3 +76,3 @@ {

value: ['Mark'],
previous: ['Steve Miller'],
previous: ['Mark'], // when resolved, previous always equals value
isWaiting: false,

@@ -93,5 +93,5 @@ isResolved: true,

### Usage in redux
An serious problem with the above code is that when the promise resolves, the app doesn't re-render to show the new data. Instead of simply logging the employees in the onResolve callback, we need to dispatch an action to tell the app to re-render and call the selector. This is a bit of a hack because nothing in the state was changed. One thing to make sure of is the action that is called action changes state in some way or a re-render event won't be triggered. Another thing to be careful of is recursion resulting from the action causing the inputs of the selector to change.
A serious problem with the above code is that when the promise resolves, the app doesn't re-render to show the new data. Instead of simply logging the employees in the onResolve callback, we need to dispatch an action to tell the app to re-render and call the selector. This is a bit of a hack because nothing in the state was changed. One thing to make sure of is that the action changes state in some way or a re-render event won't be triggered. Another thing to be careful to avoid is recursion resulting from the action causing the inputs of the selector to change.
```
```js
const triggerRerender = () => {

@@ -114,3 +114,3 @@ return {

```
```js
// ....

@@ -133,3 +133,3 @@ const employees = createAsyncSelector(params, [getSearchText]);

```
```js
function buttonClicked() {

@@ -142,7 +142,21 @@ employeeAges(store.getState(), true) // "true" indicates that the selector should create a new promise regardless of whether the inputs changed

### Throttling queries
Often, you don't want to send queries too frequently. For example, if the user is typing into a textfield, you might only want to send a query after the user finished, so as to not spam the API. To solve this, you can use the "throttle" parameter.
```js
import _ from 'underscore';
const params = {
sync: (searchText) => [],
async: getEmployees,
throttle: f => _.debounce(f, 250),
}
```
Internally, a debounced version of the selector is generated and it is (recursively) called every time the selector is called (if the inputs were changed).
# Documentation
createAsyncSelector takes in two arguments:
```
```js
function createAsyncSelector(params, ...selectors) -> obj

@@ -162,3 +176,3 @@ ```

Each selector is a function that takes in state as its argument just like in reselect. It memoizes its results so the only way for it to return a different value for the same inputs is if it contained a promise that was resolved. An async selector is only different from a normal selector in that you can pass in "forceUpdate" bool as the second parameter to force a promise to be made.
```
```js
function selector(state, forceUpdate=false) -> any

@@ -169,3 +183,3 @@ ```

### params.sync (Required)
```
```js
function sync(...selectorResults) -> any

@@ -175,3 +189,3 @@ ```

### params.async (Required)
```
```js
function async(...selectorResults) -> promise

@@ -181,3 +195,3 @@ ```

### params.onResolve
```
```js
function onResolve(resolvedValue, ...selectorResults) -> void

@@ -187,3 +201,3 @@ ```

### params.onReject
```
```js
function onReject(rejectedValue, ...selectorResults) -> void

@@ -193,3 +207,3 @@ ```

### params.onCancel
```
```js
function onCancel(cancelledPromise, ...selectorResults) -> void

@@ -199,3 +213,3 @@ ```

### params.shouldUseAsync
```
```js
function shouldUseAsync(...selectorResults) -> bool

@@ -205,5 +219,11 @@ ```

### params.omitStatus
```
```js
omitStatus: bool
```
This is a convenience variable. If it is set to true, the selector will only output a value not the entire object.
### params.throttle
```js
function throttle(func) -> func
```
This function is passed a selector and the new version of that function is recursively called every time the selector is called and the inputs were changed.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc