簡體   English   中英

ReactJS 無法使用 event.persist() 從事件設置狀態

[英]ReactJS can't set state from an event with event.persist()

我需要設置一個從事件中獲取的狀態字段,但是當我將函數傳遞給它時它不會被設置。 組件和方法如下所示:

constructor(props: SomeProps, context: any) {
  super(props, context);
  this.state = {
    isFiltering: props.isFiltering,
    anchor: "",
  };
}

private toggleFilter = (event: any) => {
  event.persist()
  this.setState(prevState => ({
    isFiltering: !prevState.isFiltering,
    anchor: event.currentTarget // does not work, it's null
  }));
}

如果我刪除event.persist()然后我收到以下錯誤:

出於性能原因重用此合成事件。 如果您看到這一點,則表示您正在訪問已發布/已取消的合成事件的方法currentTarget 這是一個空操作函數。 如果您必須保留原始合成事件,請使用 event.persist()。 有關詳細信息,請參閱https://facebook.github.io/react/docs/events.html#event-pooling

由於某種原因,以下代碼有效:

private toggleFilter = (event: any) => {
  this.setState({anchor:event.currentTarget}) // works fine
  this.setState(prevState => ({
    isFiltering: !prevState.isFiltering,
  }));
}

為什么上面的方法有效,但當我使用this.setState(prevState=>...)

這是預期的行為,因為event.persist()並不意味着currentTarget沒有被取消,事實上它應該是 - 這符合瀏覽器的本機實現。

這意味着如果您想以異步方式訪問 currentTarget ,則需要像您在答案中那樣將其緩存在變量中。


引用其中一位 React 核心開發人員 - Sophie Alpert

currentTarget 隨着事件的冒泡而改變——如果您在接收事件的元素上有一個事件處理程序,而在其祖先上有其他事件處理程序,他們會看到不同的 currentTarget 值。 IIRC 取消它與本地事件發生的情況一致; 如果沒有,請告訴我,我們將重新考慮我們的行為。

查看官方 React 存儲庫中討論的來源,以及 Sophie 提供的以下片段,我已經稍微觸及了一下。

 var savedEvent; var savedTarget; divb.addEventListener('click', function(e) { savedEvent = e; savedTarget = e.currentTarget; setTimeout(function() { console.log('b: currentTarget is now ' + e.currentTarget); }, 0); }, false); diva.addEventListener('click', function(e) { console.log('same event object? ' + (e === savedEvent)); console.log('same target? ' + (savedTarget === e.currentTarget)); setTimeout(function() { console.log('a: currentTarget is now ' + e.currentTarget); }, 0); }, false);
 div { padding: 50px; background: rgba(0,0,0,0.5); color: white; }
 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div id="diva"><div id="divb"> Click me and see output! </div></div> </body> </html>

通過 @thirtydot 的評論,我得到了一個可行的解決方案。

我認為這是因為 setState 是“異步的”,所以當你傳遞給 setState 的函數被執行(並且事件被訪問)時,事件已經不存在了。 在第二個版本中,立即訪問事件並將其 currentTarget 傳遞給 setState

所以我將event.currentTarget存儲到一個變量並使用它,正如ReactJs 事件池中所解釋的那樣

看起來像這樣並且有效

private toggleFilter = (event: any) => {
        let target = event.currentTarget;   
        this.setState((prevState) => ({
            isFiltering: !prevState.isFiltering,
            anchor: target
        }));
    }

然而,這並不能解釋為什么event.persist()不起作用。 我會接受解釋它的答案。

要解決此問題 - 在調用表單的 handleSubmit 之前,調用 event.persist() 然后在 handleSubmit() 定義中 - 編寫您的邏輯。 例如

<form id="add_exp_form" onSubmit={(event) => {event.persist();this.handleSubmit(event)}}>

handleSubmit(event){
    // use event.currentTarget - It will be visible here
}

在您的函數中,您應該使用 const event.preventDefault()event.prevent()

例子:

updateSpecs1 = (event) => { 
    event.preventDefault()

我在動態填充組件時遇到了類似的警告消息,為了解決這個問題,我只需要用箭頭函數包裝函數。

從:

{ text: "Delete item", onClick: deleteItem },

到:

{ text: "Delete item", onClick: (id) => deleteItem(id) },

關於這個問題有一個很好的描述和 2 個不同的解決方案,您可以查看此鏈接

您可以像這樣使用柯里化函數來處理它。

const persistEvent = (fun: any) => (e: any) => {
e.persist();
fun(e);
};

現在你可以像這樣寫你的函數

persistEvent(toggleFilter);

它將是這樣的:

const persistEvent = (fun: any) => (e: any) => {
    e.persist();
    fun(e);
    };

const delayedFunctionality = (e) => {
  setTimeout(()=> {
     console.log(e.target.value)
  },500
}

<input onChange={persistEvent(delayedFunctionality)} />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM