我在react.js应用中使用触控手势时遇到问题。问题是每个setState调用都会调用render()函数,而不仅仅是在最后。只有在使用Hammer.js处理点击时才会发生这种情况。如果使用常规按钮,则只调用一次render()函数。
有几点需要注意:
以下是我尝试尽可能简单的示例(该示例没有意义,但说明了问题):
import React from 'react';
import ReactDOM from 'react-dom';
import Hammer from 'hammerjs';
class Game extends React.Component {
constructor(props) {
super(props);
this.state = { value: 1 };
}
action() {
console.log(1)
this.setState({ value: 1 });
console.log(2)
this.setState({ value: 2 });
console.log(3)
this.setState({ value: 3 });
console.log(4)
this.setState({ value: 4 });
console.log(5)
}
componentDidMount() {
this.hammer = Hammer(this._touchdiv);
this.hammer.on('tap', () => this.action());
}
componentWillUnmount() {
this.hammer.off('tap', this.action)
}
render() {
console.log('Render');
return (
<div>
{this.state.value}
<div ref={(el) => this._touchdiv = el}> Touch div</div>
<button onClick={() => this.action()} value='update' >Normal button</button>
</div>
);
}
}
ReactDOM.render(<Game />, document.getElementById('root'));
使用常规按钮时的控制台输出:
1
2
3
4
5
Render
使用“touch div”时的控制台输出:
1
Render
2
Render
3
Render
4
Render
5
我试图谷歌但却找不到任何类似的例子。
知道发生了什么事吗?欢迎任何可能的解决方案。
编辑1:
ReyHaynes建议裁判可能是问题所在。我试图改变
<div ref={(el) => this._touchdiv = el}> Touch div</div>
到
<div className='xxx'> Touch div</div>
并更改了
this.hammer = Hammer(this._touchdiv);
到
this.hammer = Hammer(document.getElementsByClassName("xxx")[0]);
结果完全一样。是的,这是脏代码,但它说明问题存在而不使用ref。
答案 0 :(得分:0)
使用引用时,一旦状态发生更改,您将重新呈现UI中依赖于该状态的所有组件。
React将确保只更新DOM的正确位,使整个事情变得高效,但调用render来检查必要的更改。
以下是关于该文档的文档:https://reactjs.org/docs/refs-and-the-dom.html
基本上,触摸代码的这一部分导致let calendarUtil = CalendarUtility(title: event.title, location: event.location, notes: event.notes, managedObjectContext: managedObjectContext)
运行:
render()
答案 1 :(得分:0)
检查调用堆栈似乎与触发回调的方式不同。
如果手势被识别,Hammer只会调用回调。
React捕获click事件并将标志'isBatchingUpdates'设置为true,从而使渲染要等到所有setState完成。
编辑: 发现这篇文章解释为:https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60
“当前(第16和更早的版本),默认情况下,仅批处理React事件处理程序中的更新。”