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

React合成事件 —— SyntheticEvent #18

Open
oliver1204 opened this issue Feb 15, 2019 · 0 comments
Open

React合成事件 —— SyntheticEvent #18

oliver1204 opened this issue Feb 15, 2019 · 0 comments

Comments

@oliver1204
Copy link
Owner

oliver1204 commented Feb 15, 2019

先来看一下,下面这个例子有什么问题?

class App extends React.Component {

    state = { search: '' }

     handleChange = event => {

     /**
     * 这是“防抖”函数的简单实现,它会以队列的方式在 250 ms 内调用
     * 表达式并取消所有挂起的队列表达式。以这种方式我们可以在用户停止输
     * 入时延迟 250 ms 来调用表达式。
     */
    clearTimeout(this.timeout);
    this.timeout = setTimeout(() => {
      this.setState({
        search: event.target.value
      })
    }, 250);
  }

render() {
    return (
      <div>
        <input type="text" onChange={this.handleChange} />
        {this.state.search ? <p>Search for: {this.state.search}</p> : null}
      </div>
    )
  }
}

好,这道题就需要一些解释了。在防抖函数中并没有错误。那么应用会按期望方式运行吗?它会在用户停止输入的 250 ms 之后更新并且渲染字符串“Search for: …”吗?

这里的问题是在 React 中 event 是一个 SyntheticEvent,如果和它的交互被延迟了(例如:通过 setTimeout),事件会被清除并且 .target.value 引用不会再有效。

合成事件

注意:

如果要以异步方式访问事件属性,应该对事件调用 event.persist() ,这将从池中删除合成事件,并允许> 用户代码保留对事件的引用。

class App extends React.Component {
     ....
     handleChange = event => {
        event.persist();

        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
             console.log(event.target.value) // 正常了!
             this.setState({
                    search: event.target.value
             })
        }, 250);
  }

render() {
    ...
  }
}

为什么有合成事件的抽象?

listView = list.map((item,index) => {
    return (
        <p onClick={this.handleClick.bind(this, item.id)} key={item.id}>{item.text}</p>
    );
})

顺着上面的这个我们再熟悉不过的例子,想一下,假如:list 有 10000 项会怎么样呢?

  • 天哪,我生产了一万个几乎一模一样的函数?
  • 是的。
  • 天哪,我操作了一万次 DOM?
  • 哦,那倒是没有。

所以如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。

原理

React中,如果需要绑定事件,我们常常在jsx中这么写:

<div onClick={this.onClick}>
    react事件
</div>

原理大致如下:
React并不是将click事件绑在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。
以上面的代码为例,整个事件生命周期示意如下:

其中,由于event对象是复用的,事件处理函数执行完后,属性会被清空,所以event的属性无法被异步访问.

React事件--1
React事件--2

属性

SyntheticEvent 对象都具有以下属性:

boolean bubbles // 检测事件是否是冒泡事件
boolean cancelable // 指示事件是否可拥可取消的默认动作
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase  //返回事件传播的当前阶段
boolean isTrusted
DOMEvent nativeEvent // 原生事件的方法
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type
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

No branches or pull requests

1 participant