Skip to content

Commit c746613

Browse files
authored
MobX 6 support (#34)
* MobX 6 support * v2.0.0-beta.1 * update node version for ci
1 parent 0e82a2f commit c746613

File tree

8 files changed

+2572
-903
lines changed

8 files changed

+2572
-903
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
node-version: [8.x, 10.x, 12.x]
18+
node-version: [10.x, 12.x, 14.x]
1919

2020
steps:
2121
- uses: actions/checkout@v1

package-lock.json

Lines changed: 2502 additions & 872 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "formstate-x",
3-
"version": "1.2.0",
3+
"version": "2.0.0-beta.1",
44
"description": "Extended alternative for formstate",
55
"repository": {
66
"type": "git",
@@ -26,20 +26,20 @@
2626
"formstate"
2727
],
2828
"peerDependencies": {
29-
"mobx": ">=4.0.0"
29+
"mobx": ">=6.0.0"
3030
},
3131
"author": "[email protected]",
3232
"license": "Apache-2.0",
3333
"devDependencies": {
3434
"@types/jest": "^25.2.1",
3535
"@types/node": "^12.7.12",
36-
"formstate": "^1.0.0",
37-
"jest": "^25.2.7",
38-
"mobx": "^5.15.4",
39-
"ts-jest": "^25.3.1",
36+
"formstate": "^2.0.0",
37+
"jest": "~26.6.1",
38+
"mobx": "^6.0.4",
39+
"ts-jest": "~26.4.2",
4040
"typedoc": "~0.16.11",
4141
"typedoc-twilio-theme": "^1.0.0",
42-
"typescript": "^3.6.3"
42+
"typescript": "~4.0.3"
4343
},
4444
"dependencies": {}
4545
}

src/fieldState.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { observable, computed, action, reaction, autorun, runInAction, when } from 'mobx'
1+
import { observable, computed, action, reaction, autorun, when, makeObservable } from 'mobx'
22
import { ComposibleValidatable, Validator, Validated, ValidationResponse, ValidateStatus, Error, ValidateResult } from './types'
33
import { applyValidators, debounce, isPromiseLike } from './utils'
44
import Disposable from './disposable'
@@ -137,15 +137,15 @@ export default class FieldState<TValue> extends Disposable implements Composible
137137
return
138138
}
139139

140-
runInAction('set-validateStatus-when-_validate', () => {
140+
action('set-validateStatus-when-_validate', () => {
141141
this._validateStatus = ValidateStatus.Validating
142-
})
142+
})()
143143

144144
const response = applyValidators(value, this._validators)
145145

146-
runInAction('set-validation-when-_validate', () => {
146+
action('set-validation-when-_validate', () => {
147147
this.validation = { value, response }
148-
})
148+
})()
149149
}
150150

151151
/**
@@ -154,11 +154,11 @@ export default class FieldState<TValue> extends Disposable implements Composible
154154
async validate(): Promise<ValidateResult<TValue>> {
155155
const validation = this.validation
156156

157-
runInAction('activate-and-sync-_value-when-validate', () => {
157+
action('activate-and-sync-_value-when-validate', () => {
158158
this._activated = true
159159
// 若有用户交互产生的变更(因 debounce)尚未同步,同步之,确保本次 validate 结果是相对稳定的
160160
this.value = this._value
161-
})
161+
})()
162162

163163
// 若 `validation` 未发生变更,意味着未发生新的校验行为
164164
// 若上边操作未触发自动的校验行为,强制调用之
@@ -219,19 +219,21 @@ export default class FieldState<TValue> extends Disposable implements Composible
219219
return
220220
}
221221

222-
runInAction('endValidation', () => {
222+
action('endValidation', () => {
223223
this.validation = undefined
224224
this._validateStatus = ValidateStatus.Validated
225225

226226
if (error !== this.error) {
227227
this.setError(error)
228228
}
229-
})
229+
})()
230230
}
231231

232232
constructor(private initialValue: TValue, delay = 200) {
233233
super()
234234

235+
makeObservable(this)
236+
235237
this.reset()
236238

237239
// debounced reaction to `_value` change
@@ -242,11 +244,11 @@ export default class FieldState<TValue> extends Disposable implements Composible
242244
// see https://github.com/mobxjs/mobx/issues/1956
243245
debounce(() => {
244246
if (this.value !== this._value) {
245-
runInAction('sync-value-when-_value-changed', () => {
247+
action('sync-value-when-_value-changed', () => {
246248
this.value = this._value
247249
this._validateStatus = ValidateStatus.NotValidated
248250
this._activated = true
249-
})
251+
})()
250252
}
251253
}, delay),
252254
{ name: 'reaction-when-_value-change' }

src/formState.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { observable, computed, isArrayLike, isObservable, action, autorun, runInAction, when, reaction } from 'mobx'
1+
import { observable, computed, isObservable, action, autorun, when, reaction, makeObservable } from 'mobx'
22
import { ComposibleValidatable, ValueOfFields, ValidationResponse, Validator, Validated, ValidateStatus, Error, ValidateResult } from './types'
3-
import { applyValidators, isPromiseLike } from './utils'
3+
import { applyValidators, isPromiseLike, isArrayLike } from './utils'
44
import Disposable from './disposable'
55

66
/** Mode: object */
@@ -187,24 +187,24 @@ export default class FormState<TFields extends ValidatableFields, TValue = Value
187187
private _validate() {
188188
const value = this.value
189189

190-
runInAction('set-validateStatus-when-_validate', () => {
190+
action('set-validateStatus-when-_validate', () => {
191191
this._validateStatus = ValidateStatus.Validating
192-
})
192+
})()
193193

194194
const response = applyValidators(value, this._validators)
195195

196-
runInAction('set-validation-when-_validate', () => {
196+
action('set-validation-when-_validate', () => {
197197
this.validation = { value, response }
198-
})
198+
})()
199199
}
200200

201201
/**
202202
* Fire a validation behavior.
203203
*/
204204
async validate(): Promise<ValidateResult<TValue>> {
205-
runInAction('activate-when-validate', () => {
205+
action('activate-when-validate', () => {
206206
this._activated = true
207-
})
207+
})()
208208

209209
this._validate()
210210
this.fields.forEach(
@@ -262,19 +262,21 @@ export default class FormState<TFields extends ValidatableFields, TValue = Value
262262
return
263263
}
264264

265-
runInAction('endValidation', () => {
265+
action('endValidation', () => {
266266
this.validation = undefined
267267
this._validateStatus = ValidateStatus.Validated
268268

269269
if (error !== this.error) {
270270
this.setError(error)
271271
}
272-
})
272+
})()
273273
}
274274

275275
constructor(initialFields: TFields) {
276276
super()
277277

278+
makeObservable(this)
279+
278280
this.mode = isArrayLike(initialFields) ? 'array' : 'object'
279281
this.$ = initialFields
280282

src/utils.spec.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { asyncResponsesAnd, isEmpty } from './utils'
1+
import { observable } from 'mobx'
2+
import { asyncResponsesAnd, isEmpty, isArrayLike } from './utils'
23

34
const defaultDelay = 10
45

@@ -61,3 +62,31 @@ describe('asyncResponsesAnd', () => {
6162
expect(result3).toBe('too long')
6263
})
6364
})
65+
66+
describe('isArrayLike', () => {
67+
it('should work well with array', () => {
68+
expect(isArrayLike([])).toBe(true)
69+
expect(isArrayLike([1, 2, 3])).toBe(true)
70+
})
71+
it('should work well with observable array', () => {
72+
expect(isArrayLike(observable([]))).toBe(true)
73+
expect(isArrayLike(observable([1, 2, 3]))).toBe(true)
74+
})
75+
it('should recognize non-object values', () => {
76+
expect(isArrayLike(null)).toBe(false)
77+
expect(isArrayLike(undefined)).toBe(false)
78+
expect(isArrayLike(0)).toBe(false)
79+
expect(isArrayLike('123')).toBe(false)
80+
expect(isArrayLike(/abc/)).toBe(false)
81+
})
82+
it('should recognize normal objects', () => {
83+
expect(isArrayLike({})).toBe(false)
84+
expect(isArrayLike({ 0: 'a' })).toBe(false)
85+
expect(isArrayLike({ a: 1, b: 2 })).toBe(false)
86+
expect(isArrayLike(observable({ a: 1, b: 2 }))).toBe(false)
87+
})
88+
it('should recognize object with invalid length', () => {
89+
expect(isArrayLike({ length: -1 })).toBe(false)
90+
expect(isArrayLike({ length: 2.3 })).toBe(false)
91+
})
92+
})

src/utils.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Validator, ValidationResponse, ValidatorResponse } from "./types"
1+
import { isObservableArray, IObservableArray } from 'mobx'
2+
import { Validator, ValidationResponse, ValidatorResponse } from './types'
23

34
export function isPromiseLike(arg: any): arg is Promise<any> {
45
return arg != null && typeof arg === 'object' && typeof arg.then === 'function'
@@ -65,3 +66,7 @@ export function debounce(fn: () => void, delay: number) {
6566
timeout = setTimeout(fn, delay)
6667
}
6768
}
69+
70+
export function isArrayLike(value: unknown): value is unknown[] | IObservableArray {
71+
return Array.isArray(value) || isObservableArray(value)
72+
}

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"moduleResolution": "node",
1010
"strict": true,
1111
"experimentalDecorators": true,
12+
"useDefineForClassFields": true,
1213
"outDir": "./lib",
1314
"lib": ["es2015"]
1415
},

0 commit comments

Comments
 (0)