Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form 组件结合类似 Redux 等框架,外部 store 存储 fields 。修改会重复触发 onFieldsChange #2934

Closed
clarkhan opened this issue Sep 2, 2016 · 23 comments
Assignees

Comments

@clarkhan
Copy link

clarkhan commented Sep 2, 2016

本地环境

  • antd 版本: 1.11.0
  • 操作系统及其版本:Win7
  • 浏览器及其版本: Chrome 50

你做了什么?

redux 结合 From 使用。表单修改一次。

你期待的结果是:

Form 的 onFieldsChange 被触发一次, redux 的 Action 与 reducer 执行一次

实际上的结果:

onFieldsChange 触发两次。导致其他逻辑也重复执行。

可重现的在线演示

为防止其他库干扰,已全部去掉。只用 React 和 antd Form 实现(打开 Console,修改表单数据):

http://codepen.io/clarkhan/pen/vXYRgz?editors=1010

@wuyezhong
Copy link

和redux结合的时候,我这边也有这个问题,并且onFieldsChange触发三次,导致表单输入的时候非常卡顿

@wuyezhong
Copy link

@clarkhan 你好,你那边目前有什么解决方案吗?

@clarkhan
Copy link
Author

clarkhan commented Sep 3, 2016

@wuyezhong 我是才发现不久,针对多次触发的问题还没啥好方案。

导致表单输入很卡的话,是不是页面比较复杂?

  • 如果可以,表单部分在单独组件内与 redux connect;
  • 不需用的 props 尽量不要传递(比如少用 {...this.props} );
  • 组件实现 shouldComponentUpdate
  • ……

总之用一些 React 优化的相关方法。:joy:
一般情况下,单纯的绑定,change 两次应该不至于非常卡顿。

我很好奇,为啥你会触发三次,难道和使用有关?

@wuyezhong
Copy link

@clarkhan 谢谢你的回复。页面到不至于复杂。就是不知道为什么会卡。
我把 onFieldsChange 删除了,然后给每一个input组件都加了 onChange 方法。发现:问题还是一样的。输入中文的时候,他会触发三次 onChange ,貌似这个毛病是 getFieldProps 弄出来的。它给 input 的属性都做了代理。卡顿的原因就是因为 onChange触发了太多次,dispatch了太多次。比如说,输入中文的时候,按一个字母,汉子还没出来,就触发了三次 dispatch 。简直没法用了

@whx76
Copy link

whx76 commented Sep 4, 2016

我在用antd做页面时也遇到性能问题 ,我是这样理解的,不知对否供大家参考,

应该是getFieldProps 出的问题,我觉得有两个问题
1、使用getFieldProps ,组件在有输入操作时其父页面整个都要render()应该是FORM组件维护了个内部state 任何getFieldProps 的组件输入操作都会更新state整个页面导致刷新。

2、各个包含getFieldProps组件在父页面刷新时其也同时刷新,所以页面内组件一多就卡。(可以将node_modules\react\lib\ReactComponentWithPureRenderMixin.js里的
shouldComponentUpdate: function (nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
加个断点就可以看出),并且getFieldProps内部不知道做了哪些内容,其非纯函数,导致shallowCompare为true必须刷新。而不包含getFieldProps的组件自己写onchange事件就不会有这个问题。

以上两点导致性能问题。

建议能否:
1、针对第一个问题, FORM内维护state给个回调接口,缺省自动更新,也可设置为自己决定更新时机。
2、对第二个问题,优化各个控件,在外部prop没有变化时不进行render。getFieldProps纯函数实现。

@cqqccqc
Copy link

cqqccqc commented Sep 5, 2016

请教一下form怎么和redux的store做双向的绑定?我现在在onFieldsChange里调用action更新store,但是store里的值被更新后并不会更新form。有没有方便的方法做到?

@clarkhan
Copy link
Author

clarkhan commented Sep 6, 2016

@cqqccqc 你可以参照我上面提出问题的重现演示。其中的

function mapPropsToFields(props) {
  return props.fields;
}

是更新 from 内容的关键。

@ddcat1115 这个问题,onFieldsChange 重复被触发,觉得应该像 bug 更多一点。

@binzeehale
Copy link

我也有遇到触发3次,是为什么呢, 1.11.2的版本
image

@benjycui
Copy link
Contributor

onFieldsChange 触发两次。

这个是正常的,@clarkhan 认真对比下除了 value 之外的字段,你会发现真的改变了。

@wuyezhong 触发三次的问题,麻烦提供重现 demo。

Please provide a re-producible demo: http://codepen.io/benjycui/pen/KgPZrE?editors=001

@clarkhan
Copy link
Author

@benjycui 的确,其他字段有改变,是 antd 内部实现逻辑必须要这样的过程吗?

感觉修改一次,触发一次 onChange 更合理点,两次有点怪怪的 😟

@benjycui
Copy link
Contributor

field 除了包含用户输入,还包含校验状态之类,可以同步到 redux 上,甚至持久化,用户刷新页面也能保证这些状态正常显示。

@luckyyang
Copy link

确实触发了两次,我看到validating由true变成了false

@yesmeck
Copy link
Member

yesmeck commented Oct 28, 2016

@yiminghe 这个我来看看吧

@yesmeck yesmeck self-assigned this Nov 1, 2016
@yesmeck
Copy link
Member

yesmeck commented Nov 2, 2016

onFieldsChange 触发两次是预期的行为,上面已经有说明了,这个我先关了,其他问题另外开 issue 吧。

@yesmeck yesmeck closed this as completed Nov 2, 2016
@benjycui
Copy link
Contributor

benjycui commented Nov 2, 2016

可以在 onFieldsChange 里面判断 field.value 是否改变,再触发 onChange,如这个 例子 可像下面这样修改:

```jsx Form.create({ onFieldsChange(props, changedFields) { cosnt isValueChanged = Object.keys(changedFields) .some(field => props[field].value !== changedFields[field].value); if (isValueChanged) { props.onChange(changedFields); } } }); ```

@caolvchong
Copy link
Contributor

@benjycui
cosnt isValueChanged -> const

另外,这个判断是没用的,两次的props是同一个,所以还是会触发两次

@benjycui
Copy link
Contributor

benjycui commented Nov 7, 2016

@caolvchong @clarkhan 确认一下,onFieldsChange 执行两次,导致了你们哪些逻辑执行了两次然后给你们带来了什么困扰?

最好给出一个实际点的 demo

@caolvchong
Copy link
Contributor

@benjycui
onFieldsChange 按文档上说的

当 Form.Item 子节点的值发生改变时触发,可以把对应的值转存到 Redux store

在这里同步值给redux(调用redux action),会执行两次一样的操作,这其实是超出使用者的预期行为的,虽然两次onFieldsChange没有什么副作用

@clarkhan 给的例子其实就可以了,只是里面的 console.log 改成 redux action,但不影响问题呈现

@benjycui
Copy link
Contributor

benjycui commented Nov 7, 2016

在这里同步值给redux(调用redux action),会执行两次一样的操作,这其实是超出使用者的预期行为的,虽然两次onFieldsChange没有什么副作用

并没有超出预期,因为 fields 并不仅是 value。

@futianyang
Copy link

@cqqccqc 你调用action时遇到表单刷新的问题吗

@lcoder
Copy link

lcoder commented Feb 4, 2018

建议onFieldsChange调用两次的情况,文档注明下,一般人直觉应该是一次。我就碰到了这个违反直觉的东西,然后google之,带到这里,知道原因

@afc163
Copy link
Member

afc163 commented Feb 6, 2018

可以用 onValuesChange

@lcoder
Copy link

lcoder commented Feb 7, 2018

const CustomizedForm = Form.create({
  onFieldsChange(props, changedFields) {
    // 倘若注释这一行代码,表单项的值依旧可以改变,是不是不符合受控组件的概念?
    props.actionChangedFields( changedFields ) ;
  },
  mapPropsToFields(props) {
    return {
      username: Form.createFormField({
        ...props.username,
        value: props.username.value,
      }),
    };
  },
  onValuesChange(_, values) {
    console.log(values);
  },
})

纯属讨论,我发现我用redux绑定了表单的值,从redux中拿到值,然后用createFormField注册。按理说表单项应该受控了。倘若onFieldsChange什么也不做,表单项的值,应该是初始化的值。可是实际执行的时候,视觉上,值还是可以改变的,虽然没有通过actionChangedFields( changedFields ) ;通知redux更新,数据中心的值确实没变,不过视觉上感觉数据是变了。
这个例子:integrate with redux
注释如下代码,可以复现:

onFieldsChange(props, fields) {
    console.log('onFieldsChange', fields);
    //props.dispatch({
    //  type: 'save_fields',
    //  payload: fields,
    //});
  },

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

No branches or pull requests