Skip to content

Conversation

@nighca
Copy link
Collaborator

@nighca nighca commented Apr 17, 2022

Changes of v3

See #47 for details.

Migrating from v2

Breaking Changes

1. Naming Adjustment

  • interface Validatable & ComposibleValidatable -> interface IState

  • state.validators() -> state.withValidator()(for details: [discussion] api naming #20

  • state.diableValidationWhen() -> state.disableWhen()(for details: disable & disable validation #17

  • state.dirty -> state.touched

    Note that behaviors of the two fields differ (for details: Details for dirty & DebouncedState #74 Opt-in debouncing #63):

    • dirty tells if current value (value) equals initial value (initialValue)
    • touched tells if any change ever happened

    Which means, for code like:

    const state = new FieldState(0)
    state.set(1)
    state.set(0)

    in v2, the result state.dirty will be false; in v3, the result state.touched will be true

    P.S. state.reset() will reset state.touched to false

2. Changes of FieldState

In v3, we now no longer debounce value change of FieldState. Correspondingly, it is not supported to specify delay (of debouncing) when constructing FieldState instances now (for details: #61).

If you need the debouncing of value change, you can use DebouncedFieldState instead. It's almost the same as FieldState in v2:

const state = new DebouncedFieldState(1) // with default delay: 200ms
const state = new DebouncedFieldState(1, 500) // with delay: 500ms

As a result, field _value of FieldState instances is removed and UI binding is simplified: bindInput is no longer provided in v3, just use state.value & state.onChange to bind states to UI inputs:

<input
  value={state.value}
  onChange={e => state.onChange(e.target.value)}
/>

Note that if state is an instance of DebouncedFieldState, you should use state.$ instead of state to do binding (for details: Debounced State).

3. FormState[mode=array] -> ArrayFormState

In v2, there are two modes for FormState: object / array, corresponding for two cases:

  • [mode=object]

    const state = new FormState({ foo: fooState, bar: barState })
  • [mode=array]

    const state = new FormState([foo, bar].map(createChildState))

In v3, the mode object remains the same. Mode array is not supported any more, and we provided class ArrayFormState for the array cases:

const state = new ArrayFromState([foo, bar], createChildState)

Its APIs differs slightly, for details: Input List & #54

4. Others

  • Field $ of FormState instances is now read-only, which means, behaviors like state.$.foo = ... is no longer allowed
  • Field $ of FieldState instances is removed
  • isFormState is removed

Other important (while not breaking) changes

1. TransformedState

For situations where UI value differs with business value, we provide TransformedState. It works perfect within composition, for details: Transformed State & #56

2. set & onChange

In v2, only FieldState instances provided methods set & onChange to change their value. If you want to change the value of a FormState instance, you need to access its child states (state.$.*) first. In v3, you can call set or onChange directly on any state, as long as it implemented interface IState. The semantics for these methods remains the same.

Compare

// v3
const state = new FormState({ foo: fooState, bar: barState })
state.set({ foo: 1, bar: 2 })

with

// v2
const state = new FormState({ foo: fooState, bar: barState })
state.$.foo.set(1)
state.$.bar.set(2)

The way in v3 (state.set({ foo: 1, bar: 2 })) is much simpler, and it introduces lower coupling between parent states and child states.

3. ownError & hasOwnError

In v2, only instances of FormState provided fields ownError & hasOwnError. In v3, you can access ownError & hasOwnError on any states which implemented interface IState. And they are recommended (instead of error & hasError) for UI binding purpose. for details: #71

4. The brand-new docs

We built brand-new documents site for v3. It will be helpful to read them first, especially for key concepts in formstate-x.


v3 变更

详见 #47

升级文档

不兼容变更

1. 命名调整

  • interface Validatable & ComposibleValidatable -> interface IState

  • state.validators() -> state.withValidator()(详见 [discussion] api naming #20

  • state.diableValidationWhen() -> state.disableWhen()(详见 disable & disable validation #17

  • state.dirty -> state.touched

    注意该字段的行为也有所调整(详见 Details for dirty & DebouncedState #74 Opt-in debouncing #63):

    • dirty 代表的是当前值(value)跟初始值(initialValue)是否不相等
    • touched 代表的是值是否 发生过 变更(仅 reset 会将该状态重置)

    即,以下的行为

    const state = new FieldState(0)
    state.set(1)
    state.set(0)

    对于 v2,结果 state.dirtyfalse;对于 v3,结果 state.touchedtrue

    P.S. state.reset() 会将 state.touched 重置为 false

2. FieldState 变更及输入控件的绑定

v3 中 FieldState 不再对 value 变更添加 debounce,对应地也不再支持在构造 FieldState 时指定 debounce 的 delay(详见 #61

如果业务上确实需要对 value 变更 debounce 后再去响应,可以使用 DebouncedFieldState 代替;DebouncedFieldState 的构造方式与 v2 中的 FieldState 一致:

const state = new DebouncedFieldState(1) // with default delay: 200ms
const state = new DebouncedFieldState(1, 500) // with delay: 500ms

对应地,FieldState 上的字段 _value 也被移除,因此绑定 UI 的方式会有调整:formstate-x v3 不再提供 bindInput;要将 state 与输入控件进行绑定,直接使用 state.value & state.onChange 即可。如:

<input
  value={state.value}
  onChange={e => state.onChange(e.target.value)}
/>

注意,若 stateDebouncedFieldState 实例 ,应当使用 state.$ 而不是 state 进行绑定(详见 Debounced State)。

3. FormState[mode=array] -> ArrayFormState

v2 的 FormState 支持 object / array 两种模式(mode),分别对应两种不同的使用姿势:

  • [mode=object]

    const state = new FormState({ foo: fooState, bar: barState })
  • [mode=array]

    const state = new FormState([foo, bar].map(createChildState))

在 v3 中,第一种使用姿势与 v2 一致;对于第二种使用姿势(对应于输入是一个长度不定的列表的情况),我们单独提供了 ArrayFormState 来满足这样的场景:

const state = new ArrayFromState([foo, bar], createChildState)

ArrayFromState 的使用与原 FormState 也会有所区别,详见 Input List & #54

4. 其他

  • FormState 实例的 $ 调整为 readonly,即不再允许类似 state.$.foo = ... 的操作
  • FieldState 实例的 $ 被移除
  • isFormState 被移除

其他值得了解的变更

1. TranformedState

对于 UI value 与 business value 不一致的情况,我们过去通过由 Input 组件导出 getValue 来实现。在 v3 中,我们提供了 TranformedState 来处理这种诉求,它的好处是不会要求 Input 组件提供额外的导出(getValue),对 Input 组件的使用者也更友好(直接使用 state.value 即可),对应地,其可组合性也会更好。详见 Transformed State & #56

2. set & onChange

在 v2 中,仅 FieldState 实例提供了 set / onChange 来直接操作其 value;对于 FormState 实例,往往需要去通过其子 state(state.$.xxx)来实现对值的设置。在 v3 中,所有(实现了 IState 接口的)state 都会提供 onChange / set,其语义与 v2 中 FieldState 实例提供的 set / onChange 语义一致。因此你可以方便地在上层(父级 state)直接进行值的设置:

const state = new FormState({ foo: fooState, bar: barState })
state.set({ foo: 1, bar: 2 })

相比

state.$.foo.set(1)
state.$.bar.set(2)

state.set({ foo: 1, bar: 2 }) 的做法更简单,也使得上层与下层逻辑的耦合更低(父级 state 无须知道子 state 的信息)

3. ownError & hasOwnError

在 v3 中,仅 FormState 实例会提供 ownError & hasOwnError。现在所有(实现了 IState 接口的)state 实例都会提供 ownError & hasOwnError。建议使用 ownError & hasOwnError 代替 error & hasError 去实现校验结果与界面的绑定(如 bindFormItem),详见 #71

4. 阅读最新的文档

v3 提供了全新的文档( https://qiniu.github.io/formstate-x/ ),内容不长,建议阅读以便了解 formstate-x 中的关键概念

@nighca nighca mentioned this pull request Apr 17, 2022
Merged
13 tasks
@nighca nighca closed this Apr 17, 2022
@nighca nighca reopened this Apr 17, 2022
@nighca nighca merged commit b23f897 into qiniu:master Apr 18, 2022
@mattleonowicz
Copy link
Contributor

@nighca Nice to see this awesome library developed farther and farther!
Is there any chance of translating whole release notes to english?

@nighca
Copy link
Collaborator Author

nighca commented Apr 24, 2022

@mattleonowicz I will (in couple of days).

P.S. If currently you are not using any older versions of formstate-x, the release note here is not actually important. You can head to the documents directly :) That's much more detailed.

@nighca
Copy link
Collaborator Author

nighca commented Apr 24, 2022

@mattleonowicz The en version is here. Feel free if any further questions.

@mattleonowicz
Copy link
Contributor

Thank you! I'm still on v2. Will move to v3 soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants