1
- # Redux Action Selector
1
+ # Redux Selector Action
2
2
[ ![ npm package] [ npm-badge ]] [ npm ]
3
3
4
4
Same Redux "selectors" but for actions, inspired by [ reselect] ( https://github.com/reduxjs/reselect ) .
5
5
6
- * Action selectors can be dispatched as any other Redux action.
7
- * Action selectors accept store selectors to eventually inject their output to the given action creator.
8
- * Action selectors reduce the data your "containers" (components connected to redux store) need to pass.
6
+ * Selector Actions can be dispatched as any other Redux action.
7
+ * Selector Actions accept store selectors to eventually inject their output to the given action creator.
8
+ * Selector Actions reduce the data your "containers" (components connected to redux store) need to pass.
9
9
10
- An action selector accepts a list of selectors and a regular action creator
10
+ A selector- action creator accepts a list of selectors and a regular action creator
11
11
12
12
** container/actions.js**
13
13
14
14
``` js
15
- import { createActionSelector , getPlaceholder } from ' redux-action- selector' ;
15
+ import { createSelectorAction , getPlaceholder } from ' redux-selector-action ' ;
16
16
17
17
const getCsrfToken = state => state .csrfToken ;
18
18
const getCurrency = state => state .currency ;
19
19
const getLang = state => state .lang ;
20
20
21
21
22
- export const fetchOrder = createActionSelector (
22
+ export const fetchOrder = createSelectorAction (
23
23
getCsrfToken,
24
24
getPlaceholder, // placeholder for order id
25
25
getCurrency,
@@ -49,26 +49,44 @@ const mapDispatchToProps = dispatch => {
49
49
}
50
50
```
51
51
52
+ ** index.js**
53
+
54
+ ``` js
55
+ import { applyMiddleware , createStore , compose } from ' redux' ;
56
+ import { reduxSelectorActionMiddleware } from ' redux-selector-action' ;
57
+ import rootReducer from ' ./reducers' ;
58
+ import {fetchOrder } from ' ./container/actions' ;
59
+
60
+ const middlewareEnhancer = applyMiddleware (reduxSelectorActionMiddleware);
61
+ const composedEnhancers = compose (middlewareEnhancer);
62
+ const initialState = undefined ;
63
+
64
+ const store = createStore (rootReducer, initialState, composedEnhancers);
65
+
66
+ store .dispatch (fetchOrder (123 ));
67
+ ```
68
+
52
69
## Table of Contents
53
70
54
71
- [ Installation] ( #installation )
55
- - [ Motivation for Action Selectors ] ( #motivation-for-action-selectors )
72
+ - [ Motivation for Selector Actions ] ( #motivation-for-selector-actions )
56
73
- [ API] ( #api )
57
74
- [ ` getPlaceholder ` ] ( #getplaceholder )
58
- - [ ` createActionSelector ` ] ( #createactionselectorselectors--selectors-resultfunc )
75
+ - [ ` createSelectorAction ` ] ( #createactionselectorselectors--selectors-resultfunc )
76
+ - [ ` reduxSelectorActionMiddleware ` ] ( #reduxselectoractionmiddleware )
59
77
- [ FAQ] ( #faq )
60
- - [ Can I use this package without Reselect and Redux?] ( #q-can-i-use-this-package-without-reselect-and-redux )
78
+ - [ Can I use this package without Redux?] ( #q-can-i-use-this-package-without-redux )
79
+ - [ Can I use this package without Reselect?] ( #q-can-i-use-this-package-without-reselect )
61
80
- [ My action accepts many args that can't be injected, should I pass many getPlaceholders?] ( #q-my-action-accepts-many-args-that-cant-be-injected-should-i-pass-many-getplaceholders )
62
- - [ My action accepts an options object which its props can be injected, how can I inject them?] ( #q-my-action-accepts-an-options-object-which-its-props-can-be-injected-how-can-i-inject-them )
63
- - [ How can I test an action selector?] ( #q-how-can-i-test-an-action-selector )
81
+ - [ How can I test a selector action?] ( #q-how-can-i-test-a-selector-action )
64
82
- [ License] ( #license )
65
83
66
84
67
85
## Installation
68
- npm install redux-action- selector
86
+ npm install redux-selector-action
69
87
70
88
71
- ## Motivation for Action Selectors
89
+ ## Motivation for Selector Actions
72
90
Containers include in most cases some props, which they get just to pass to actions creators.
73
91
In order to avoid redundant data (props) passed to those containers, there should be a way for actions to get their data from store.
74
92
This way would let us create actions which accept only the data the container holds.
@@ -91,27 +109,21 @@ Let's fix this.
91
109
92
110
## API
93
111
94
- ### getPlaceholder()
95
- This is a built-in selector, which you can use as part of your action creator's selectors.
96
- Once you pass it as a dependency, instead of injecting the output of this selector,
97
- we save its position in the dependency list (selectors) for an arg, which will be sent once you call the action selector.
98
-
99
-
100
- ### createActionSelector(...selectors | [ ...selectors] , resultFunc)
112
+ ### createSelectorAction(...selectors | [ ...selectors] , resultFunc)
101
113
102
114
This function accept a list of selectors, or an array of selectors, computes their output against the store's state, and inject them as arguments to the given ` resultFunc ` .
103
115
104
116
[ ` getPlaceholder ` ] ( #getplaceholder ) selector will be handled separately.
105
117
106
118
``` js
107
- import { createActionSelector , getPlaceholder } from ' redux-action- selector' ;
119
+ import { createSelectorAction , getPlaceholder } from ' redux-selector-action ' ;
108
120
import {updateOrderCurrencyAction } from ' ./actions' ;
109
121
110
122
const getCsrfToken = state => state .csrfToken ;
111
123
const getOrderId = state => state .orderId ;
112
124
113
125
// We accept array of selectors too! choose your preferred way.
114
- export const updateOrderCurrency = createActionSelector (
126
+ export const updateOrderCurrency = createSelectorAction (
115
127
[getCsrfToken, getOrderId, getPlaceholder /* currency */ ],
116
128
updateOrderCurrencyAction,
117
129
);
@@ -120,37 +132,83 @@ export const updateOrderCurrency = createActionSelector(
120
132
updateOrderCurrency (' USD' );
121
133
```
122
134
135
+ ### getPlaceholder()
136
+ This is a built-in selector, which you can use as part of your action creator's selectors.
137
+ Once you pass it as a dependency, instead of injecting the output of this selector,
138
+ we save its position in the dependency list (selectors) for an arg, which will be sent once you call the selector action.
139
+
140
+ In case you have an action creator with an "options" argument (meaning an object which maps arg names to their values),
141
+ you can use the following syntax:
142
+
143
+ ``` js
144
+ import { createSelectorAction , getPlaceholder } from ' redux-selector-action' ;
145
+ import { getCsrfToken , getCurrency , getLang } from ' ./selectors' ;
146
+
147
+ export const fetchOrder = createSelectorAction (
148
+ // Map the arg names to selectors, then your action creator will get their values:
149
+ getPlaceholder ({
150
+ token: getCsrfToken,
151
+ currency: getCurrency,
152
+ lang: getLang,
153
+ }),
154
+ ({token, orderId, currency, lang}) => ({
155
+ type: ' fetch_order_request' ,
156
+ payload: {
157
+ // ...
158
+ }
159
+ })
160
+ );
161
+
162
+ // fetchOrder({orderId: 123});
163
+ ```
164
+
165
+ ### reduxSelectorActionMiddleware()
166
+ This is a redux middleware which handles our build-in selector actions.
167
+ In order to make everything work, you should add it to your store enhancers, the position does not matter.
168
+
169
+ ``` js
170
+ import { applyMiddleware , createStore , compose } from ' redux' ;
171
+ import { reduxSelectorActionMiddleware } from ' redux-selector-action' ;
172
+ import rootReducer from ' ./reducers' ;
173
+
174
+ const middlewareEnhancer = applyMiddleware (reduxSelectorActionMiddleware);
175
+ const composedEnhancers = compose (middlewareEnhancer);
176
+ const initialState = undefined ;
177
+
178
+ const store = createStore (rootReducer, initialState, composedEnhancers);
179
+ ```
180
+
123
181
## FAQ
124
182
125
- ### Q: Can I use this package without Reselect and Redux?
183
+ ### Q: Can I use this package without Redux?
126
184
127
- A: Yes. This package has no dependencies on any other package, even though it was designed to be used with Reselect and Redux.
185
+ A: No. Even though this package has no dependency on Redux, it was designed to be used with Redux.
186
+ It means we expect for example that our middleware will be called with Redux store api (store.getState(), store.dispatch()).
128
187
129
188
130
- ### Q: My action accepts many args that can't be injected, should I pass many getPlaceholders ?
189
+ ### Q: Can I use this package without Reselect ?
131
190
132
- A: Not necessarily. All args you pass to the created action selector will be injected to the placeholders.
133
- But if you pass more args than placeholders, then they will be appended too.
191
+ A: Yes. This package has no dependency on Reselect, you can work with any selectors you want, eventually they are just functions that accept state.
134
192
135
193
136
- ### Q: My action accepts an options object which its props can be injected, how can I inject them ?
194
+ ### Q: My action accepts many args that can't be injected, should I pass many getPlaceholders ?
137
195
138
- A: We are working to support also objects (options argument), it will be available soon .
139
- At the meantime, you can extract them to be regular args if you wish to .
196
+ A: Not necessarily. All args you pass to the created selector action will be injected to the placeholders .
197
+ But if you pass more args than placeholders, then they will be appended too .
140
198
141
199
142
- ### Q: How can I test an action selector?
200
+ ### Q: How can I test a selector action ?
143
201
144
- Every action selector keeps a reference to the given selectors and the action creator, as ` .dependencies ` and ` .resultFunc ` respectively.
202
+ Every selector action keeps a reference to the given selectors and the action creator, as ` .dependencies ` and ` .resultFunc ` respectively.
145
203
146
- For example if you have the following action selector:
204
+ For example if you have the following selector action :
147
205
148
- ** src/actionSelectors .js**
206
+ ** src/selectorActions .js**
149
207
``` js
150
208
export const getFirst = state => 1 ;
151
209
export const getSecond = state => 2 ;
152
210
153
- export const myActionSelector = createActionSelector (
211
+ export const mySelectorAction = createSelectorAction (
154
212
getFirst,
155
213
getSecond,
156
214
getPlaceholder,
@@ -160,19 +218,20 @@ export const myActionSelector = createActionSelector(
160
218
161
219
You can test it this way:
162
220
163
- ** test/actionSelectors .js**
221
+ ** test/selectorActions .js**
164
222
165
223
``` js
224
+ import { mySelectorAction } from ' ../src/selectorActions' ;
225
+
166
226
// test the selectors themselves...
167
227
test (" getFirst" , () => { /* ... */ });
168
228
test (" getSecond" , () => { /* ... */ });
169
229
170
- test (" myActionSelector " , () => {
230
+ test (" mySelectorAction " , () => {
171
231
// check the dependencies are as expected
172
- assert (myActionSelector .dependencies ).toEqual ([getFirst, getSecond, getPlaceholder]);
173
- // check the the resultFunc output as expected
174
- assert (myActionSelector .resultFunc (1 , 2 , 3 )).toMatchSnapshot ();
175
-
232
+ assert (mySelectorAction .dependencies ).toEqual ([getFirst, getSecond, getPlaceholder]);
233
+ // check the resultFunc output is as expected
234
+ assert (mySelectorAction .resultFunc (1 , 2 , 3 )).toMatchSnapshot ();
176
235
})
177
236
```
178
237
@@ -181,7 +240,7 @@ test("myActionSelector", () => {
181
240
182
241
[ MIT] ( ./LICENSE )
183
242
184
- [ npm-badge ] : https://img.shields.io/npm/v/redux-action- selector.svg?style=flat-square
185
- [ npm ] : https://www.npmjs.org/package/redux-action- selector
243
+ [ npm-badge ] : https://img.shields.io/npm/v/redux-selector-action .svg?style=flat-square
244
+ [ npm ] : https://www.npmjs.org/package/redux-selector-action
186
245
187
246
0 commit comments