Skip to content
This repository was archived by the owner on Aug 23, 2022. It is now read-only.

Commit fae1351

Browse files
committed
Removing thunk incrementally, pt. 1. Addresses #550
1 parent 0308e63 commit fae1351

File tree

6 files changed

+129
-76
lines changed

6 files changed

+129
-76
lines changed

src/actions/batch-actions.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,22 @@ const batch = trackable((model, actions) => {
2222
};
2323
}
2424

25-
return (dispatch) => {
26-
const [plainActions, actionThunks] = partition(dispatchableActions,
27-
(action) => typeof action !== 'function');
25+
const [plainActions, actionThunks] = partition(dispatchableActions,
26+
(action) => typeof action !== 'function');
2827

28+
if (!actionThunks.length) {
29+
if (plainActions.length > 1) {
30+
return {
31+
type: actionTypes.BATCH,
32+
model,
33+
actions: plainActions,
34+
};
35+
} else if (plainActions.length === 1) {
36+
return plainActions[0];
37+
}
38+
}
39+
40+
return (dispatch) => {
2941
if (plainActions.length > 1) {
3042
dispatch({
3143
type: actionTypes.BATCH,
@@ -35,7 +47,6 @@ const batch = trackable((model, actions) => {
3547
} else if (plainActions.length === 1) {
3648
dispatch(plainActions[0]);
3749
}
38-
3950
actionThunks.forEach(dispatch);
4051
};
4152
});

src/actions/field-actions.js

Lines changed: 53 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -167,63 +167,65 @@ function createFieldActions(s = defaultStrategies) {
167167
submitFailed,
168168
});
169169

170-
const submit = (model, promise, options = {}) => (dispatch, getState) => {
170+
const submit = (model, promise, options = {}) => {
171171
if (typeof promise === 'undefined') {
172-
return dispatch(addIntent(model, { type: 'submit' }));
172+
return addIntent(model, { type: 'submit' });
173173
}
174174

175-
if (options.validate) {
176-
const form = s.getForm(getState(), model);
177-
178-
if (!form.$form.valid) {
179-
return dispatch(NULL_ACTION);
180-
}
181-
182-
dispatch(setPending(model, true));
183-
} else if (options.validators || options.errors) {
184-
const validators = options.validators || options.errors;
185-
const isErrors = options.errors;
186-
const value = s.get(getState(), model);
187-
const validity = getValidity(validators, value);
188-
const valid = options.errors
189-
? !isValidityInvalid(validity)
190-
: isValidityValid(validity);
191-
192-
if (!valid) {
193-
return dispatch(isErrors
194-
? setErrors(model, validity)
195-
: setValidity(model, validity));
175+
return (dispatch, getState) => {
176+
if (options.validate) {
177+
const form = s.getForm(getState(), model);
178+
179+
if (!form.$form.valid) {
180+
return dispatch(NULL_ACTION);
181+
}
182+
183+
dispatch(setPending(model, true));
184+
} else if (options.validators || options.errors) {
185+
const validators = options.validators || options.errors;
186+
const isErrors = options.errors;
187+
const value = s.get(getState(), model);
188+
const validity = getValidity(validators, value);
189+
const valid = options.errors
190+
? !isValidityInvalid(validity)
191+
: isValidityValid(validity);
192+
193+
if (!valid) {
194+
return dispatch(isErrors
195+
? setErrors(model, validity)
196+
: setValidity(model, validity));
197+
}
198+
199+
dispatch(batch(model, [
200+
setValidity(model, isErrors
201+
? invertValidity(validity)
202+
: validity),
203+
setPending(model, true),
204+
]));
205+
} else {
206+
dispatch(setPending(model, true));
196207
}
197208

198-
dispatch(batch(model, [
199-
setValidity(model, isErrors
200-
? invertValidity(validity)
201-
: validity),
202-
setPending(model, true),
203-
]));
204-
} else {
205-
dispatch(setPending(model, true));
206-
}
207-
208-
const errorsAction = options.fields
209-
? setFieldsErrors
210-
: setErrors;
211-
212-
promise.then(response => {
213-
dispatch(batch(model, [
214-
setSubmitted(model, true),
215-
setValidity(model, response),
216-
]));
217-
}).catch(error => {
218-
if (!isNative) console.error(error);
219-
220-
dispatch(batch(model, [
221-
setSubmitFailed(model),
222-
errorsAction(model, error),
223-
]));
224-
});
209+
const errorsAction = options.fields
210+
? setFieldsErrors
211+
: setErrors;
212+
213+
promise.then(response => {
214+
dispatch(batch(model, [
215+
setSubmitted(model, true),
216+
setValidity(model, response),
217+
]));
218+
}).catch(error => {
219+
if (!isNative) console.error(error);
220+
221+
dispatch(batch(model, [
222+
setSubmitFailed(model),
223+
errorsAction(model, error),
224+
]));
225+
});
225226

226-
return promise;
227+
return promise;
228+
};
227229
};
228230

229231
const submitFields = (model, promise, options = {}) =>

src/components/control-component.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
272272
model,
273273
modelValue,
274274
updateOn,
275+
dispatch,
275276
} = this.props;
276277

277278
// If there are no async validators,
@@ -295,23 +296,19 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
295296

296297
if (!syncValid) return false;
297298

298-
return (dispatch) => {
299-
mapValues(asyncValidators,
300-
(validator, key) => dispatch(actions.asyncSetValidity(model,
301-
(_, done) => {
302-
const outerDone = (valid) => {
303-
const validity = i.merge(fieldValue.validity, { [key]: valid });
299+
dispatch(actions.setValidating(model, true));
304300

305-
done(validity);
306-
};
301+
mapValues(asyncValidators, (validator, key) => {
302+
const outerDone = (valid) => {
303+
const validity = i.merge(fieldValue.validity, { [key]: valid });
307304

308-
validator(getValue(valueToValidate), outerDone);
309-
})
310-
)
311-
);
305+
dispatch(actions.setValidity(model, validity));
306+
};
312307

313-
return valueToValidate;
314-
};
308+
validator(getValue(valueToValidate), outerDone);
309+
});
310+
311+
return valueToValidate;
315312
}
316313

317314
getNodeErrors() {
@@ -489,8 +486,6 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
489486
eventAction && eventAction(model),
490487
containsEvent(validateOn, eventName)
491488
&& this.getValidateAction(persistedEvent, eventName),
492-
containsEvent(asyncValidateOn, eventName)
493-
&& this.getAsyncValidateAction(persistedEvent, eventName),
494489
containsEvent(updateOn, eventName)
495490
&& this.getChangeAction(persistedEvent),
496491
];
@@ -514,7 +509,15 @@ function createControlClass(customControlPropsMap = {}, s = defaultStrategy) {
514509
)(event);
515510
}
516511

512+
517513
return compose(
514+
(e) => {
515+
if (containsEvent(asyncValidateOn, eventName)) {
516+
this.getAsyncValidateAction(e, eventName);
517+
}
518+
519+
return e;
520+
},
518521
dispatchBatchActions,
519522
parser,
520523
getValue,

test/batched-actions-spec.js

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import thunk from 'redux-thunk';
55
import { modelReducer, formReducer, actions, actionTypes } from '../src';
66

77
describe('batched actions', () => {
8-
const mockStore = configureMockStore([thunk]);
9-
108
it('should batch actions', (done) => {
9+
const mockStore = configureMockStore([thunk]);
1110
const action = actions.batch('test.foo', [
1211
actions.change('test.foo', 'testing'),
1312
actions.focus('test.foo'),
@@ -48,6 +47,39 @@ describe('batched actions', () => {
4847
store.dispatch(action);
4948
});
5049

50+
it('should batch actions without requiring thunk', (done) => {
51+
const mockStore = configureMockStore();
52+
const action = actions.batch('test.foo', [
53+
actions.change('test.foo', 'testing'),
54+
actions.focus('test.foo'),
55+
]);
56+
57+
const expectedActions = [
58+
{
59+
type: actionTypes.BATCH,
60+
model: 'test.foo',
61+
actions: [
62+
{
63+
model: 'test.foo',
64+
multi: false,
65+
silent: false,
66+
type: 'rrf/change',
67+
value: 'testing',
68+
},
69+
{
70+
model: 'test.foo',
71+
type: 'rrf/focus',
72+
value: undefined,
73+
},
74+
],
75+
},
76+
];
77+
78+
const store = mockStore({}, expectedActions, done);
79+
80+
store.dispatch(action);
81+
});
82+
5183
it('should update the form reducer with each action', () => {
5284
const reducer = formReducer('test');
5385

@@ -80,6 +112,7 @@ describe('batched actions', () => {
80112
});
81113

82114
it('should dispatch a null action if all actions are falsey', (done) => {
115+
const mockStore = configureMockStore([thunk]);
83116
const testAction = actions.batch('test.foo', [
84117
false,
85118
null,

test/form-component-spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,7 +1380,7 @@ Object.keys(testContexts).forEach((testKey) => {
13801380

13811381
assert.isFalse(store.getState().testForm.$form.valid);
13821382

1383-
store.dispatch(actions.merge('test', {
1383+
store.dispatch(actions.change('test', {
13841384
foo: 'foo valid',
13851385
bar: 'bar valid',
13861386
}));

test/utils.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ export const defaultTestContexts = {
4343
},
4444
};
4545

46-
export function testCreateStore(reducers) {
47-
return applyMiddleware(thunk)(createStore)(combineReducers(reducers));
46+
export function testCreateStore(reducers, thunk = false) {
47+
if (thunk) {
48+
return applyMiddleware(thunk)(createStore)(combineReducers(reducers));
49+
}
50+
51+
return createStore(combineReducers(reducers));
4852
}
4953

5054
export function testRender(component, store) {

0 commit comments

Comments
 (0)