Skip to content

Commit 68012eb

Browse files
committed
Merge pull request #8 from elgerlambert/refactor/selector
Refactor selector(s) api
2 parents 0de5466 + bf86140 commit 68012eb

File tree

3 files changed

+29
-41
lines changed

3 files changed

+29
-41
lines changed

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ the API is straightforward:
2020

2121
```JS
2222
$ngRedux.connect(selector, callback, disableCaching = false);
23-
//OR
24-
$ngRedux.connect([selector1, selector2, ...], callback, disableCaching = false);
2523
```
2624

27-
Where '''selector''' is a function taking for single argument the entire redux Store's state (a plain JS object) and returns another object, which is the slice of the state that your component is interested in.
25+
Where `selector` is a function that takes Redux's entire store state as argument and returns an object that contains the slices of store state that your component is interested in.
2826
e.g:
2927
```JS
30-
state => state.todos
28+
state => ({todos: state.todos})
3129
```
3230
Note: if you are not familiar with this syntax, go and check out the [MDN Guide on fat arrow functions (ES2015)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
3331

@@ -82,7 +80,7 @@ class TodoLoaderController {
8280

8381
constructor($ngRedux) {
8482
this.todos = [];
85-
$ngRedux.connect(state => state.todos, todos => this.todos = todos);
83+
$ngRedux.connect(state => ({todos: state.todos}), ({todos}) => this.todos = todos);
8684
}
8785

8886
[...]
@@ -99,11 +97,11 @@ You can also grab multiple slices of the state by passing an array of selectors:
9997
constructor(reduxConnector) {
10098
this.todos = [];
10199
this.users = [];
102-
$ngRedux.connect([
103-
state => state.todos,
104-
state => state.users
105-
],
106-
(todos, users) => {
100+
$ngRedux.connect(state => ({
101+
todos: state.todos,
102+
users: state.users
103+
}),
104+
({todos, users}) => {
107105
this.todos = todos
108106
this.users = users;
109107
});
@@ -119,7 +117,7 @@ You can close a connection like this:
119117

120118
constructor(reduxConnector) {
121119
this.todos = [];
122-
this.unsubscribe = reduxConnector.connect(state => state.todos, todos => this.todos = todos);
120+
this.unsubscribe = reduxConnector.connect(state => ({todos: state.todos}), ({todos}) => this.todos = todos);
123121
}
124122

125123
destroy() {
@@ -142,7 +140,7 @@ Each time Redux's Store update, ng-redux will check if the slices specified via
142140
You can disable this behaviour, and force the callback to be executed even if the slices didn't change by setting ```disableCaching``` to true:
143141

144142
```JS
145-
reduxConnector.connect(state => state.todos, todos => this.todos = todos, true);
143+
reduxConnector.connect(state => ({todos: state.todos}), ({todos}) => this.todos = todos, true);
146144
```
147145

148146

src/components/connector.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,21 @@ import invariant from 'invariant';
44

55
export default function Connector(store) {
66
return {
7-
connect: (selectors, callback, disableCaching = false) => {
8-
if (!Array.isArray(selectors)) {
9-
selectors = [selectors];
10-
}
11-
7+
connect: (selector, callback, disableCaching = false) => {
128
invariant(
139
isFunction(callback),
1410
'The callback parameter passed to connect must be a Function. Instead received %s.',
1511
typeof callback
1612
);
1713

1814
//Initial update
19-
let params = selectors.map(selector => selector(store.getState()));
20-
callback(...params);
15+
let params = selector(store.getState());
16+
callback(params);
2117

2218
let unsubscribe = store.subscribe(() => {
23-
let nextParams = selectors.map(selector => selector(store.getState()));
19+
let nextParams = selector(store.getState());
2420
if (disableCaching || !shallowEqual(params, nextParams)) {
25-
callback(...nextParams);
21+
callback(nextParams);
2622
params = nextParams;
2723
}
2824
});

test/components/connector.spec.js

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import expect from 'expect';
22
import {createStore} from 'redux';
3-
import {default as Connector, copyArray} from '../../src/components/connector';
3+
import Connector from '../../src/components/connector';
44

55
describe('Connector', () => {
66
let store;
@@ -25,7 +25,7 @@ describe('Connector', () => {
2525
expect(counter).toBe(1);
2626
});
2727

28-
it('Should call the function passed to connect when the store updates', () => {
28+
it('Should call the callback passed to connect when the store updates', () => {
2929
let counter = 0;
3030
let callback = () => counter++;
3131
connector.connect(state => state, callback);
@@ -34,18 +34,10 @@ describe('Connector', () => {
3434
expect(counter).toBe(3);
3535
});
3636

37-
it('Should accept a function or an array of function as selector', () => {
38-
let receivedState1, receivedState2;
39-
connector.connect(state => state.foo, newState => receivedState1 = newState);
40-
connector.connect([state => state.foo], newState => receivedState2 = newState);
41-
expect(receivedState1).toBe('bar');
42-
expect(receivedState1).toBe(receivedState2);
43-
})
44-
4537
it('Should prevent unnecessary updates when state does not change (shallowly)', () => {
4638
let counter = 0;
4739
let callback = () => counter++;
48-
connector.connect(state => state.baz, callback);
40+
connector.connect(state => ({baz: state.baz}), callback);
4941
store.dispatch({type: 'ACTION', payload: 0});
5042
store.dispatch({type: 'ACTION', payload: 0});
5143
store.dispatch({type: 'ACTION', payload: 1});
@@ -55,7 +47,7 @@ describe('Connector', () => {
5547
it('Should disable caching when disableCaching is set to true', () => {
5648
let counter = 0;
5749
let callback = () => counter++;
58-
connector.connect(state => state.baz, callback, true);
50+
connector.connect(state => ({baz: state.baz}), callback, true);
5951
store.dispatch({type: 'ACTION', payload: 0});
6052
store.dispatch({type: 'ACTION', payload: 0});
6153
store.dispatch({type: 'ACTION', payload: 1});
@@ -64,18 +56,20 @@ describe('Connector', () => {
6456

6557
it('Should pass the selected state as argument to the callback', () => {
6658
let receivedState;
67-
connector.connect(state => state.foo, newState => receivedState = newState);
68-
store.dispatch({type: 'ACTION', payload: 1});
69-
expect(receivedState).toBe('bar');
59+
connector.connect(state => ({
60+
myFoo: state.foo
61+
}), newState => receivedState = newState);
62+
expect(receivedState).toEqual({myFoo: 'bar'});
7063
});
7164

72-
it('Should pass all the selected state as argument to the callback when provided an array of selectors', () => {
73-
connector.connect([state => state.foo, state => state.anotherState],
74-
(foo, anotherState) => {
65+
it('Should allow multiple store slices to be selected', () => {
66+
connector.connect(state => ({
67+
foo: state.foo,
68+
anotherState: state.anotherState
69+
}), ({foo, anotherState}) => {
7570
expect(foo).toBe('bar');
7671
expect(anotherState).toBe(12);
77-
});
78-
store.dispatch({type: 'ACTION', payload: 1});
72+
});
7973
});
8074

8175
it('Should return an unsubscribing function', () => {

0 commit comments

Comments
 (0)