簡體   English   中英

為什么這個 onClick 事件處理程序在我的 create-react-app 中觸發兩次

[英]Why is this onClick event handler firing twice in my create-react-app

有人能告訴我為什么這個“upvote” onClick 處理程序會觸發兩次嗎? 日志表明它只運行一次,但它控制的分數增加了 2

export default class Container extends Component {
  constructor(props) {
    super(props);

    this.state = {
      jokes: [],
    };
    this.getNewJokes = this.getNewJokes.bind(this);
    this.retrieveJokes = this.retrieveJokes.bind(this);
    this.upVote = this.upVote.bind(this);
  }
upVote(id) {
    this.setState(state => {
      //find the joke with the matching id and increase score by one
      const modifiedJokes = state.jokes.map(joke => {
        if (joke.id === id) {
          
          joke.score = joke.score + 1;
          
        }
        return joke;
      });
      console.log(modifiedJokes);
      return { jokes: modifiedJokes };
    });
  }
render() {
    return (
      <div>
        <h1>Container</h1>
        {this.state.jokes.map(joke => (
          <Joke
            key={joke.id}
            id={joke.id}
            joke={joke.joke}
            score={joke.score}
            upVote={this.upVote}
            downVote={this.downVote}
          />
        ))}
      </div>
    );
  }
}

另一方面,如果我以這種方式重寫處理程序,那么它只會觸發一次

upVote(id) {
    const modifiedJokes = this.state.jokes.map(joke => {
      if (joke.id === id) {
        joke.score = joke.score + 1;
      }
      return joke;
    });
    this.setState({ jokes: modifiedJokes });
  };

這不起作用,因為 React 使用合成事件,這些事件在處理完成時會被重用。 調用setState的 function 形式將推遲評估(當setState調用依賴於事件並且事件已丟失其值時,這可能很危險)。

所以這也應該有效:

this.setState((state,props) => ({ jokes: modifiedJokes}));

我目前無法找到我的消息來源,但我記得不久前遇到過這個問題。 我確信通過 React Docs 可以提供更深入的解釋

我最好的猜測是,在第一種情況下,您還直接修改 state,當您執行 joke.score = joke.score + 1; 時

因為您直接在 state 數組變量和 Javascript 上執行此映射,所以在使用數組時,您只使用指向該數組的指針,而不是創建該數組的副本。

所以映射 function 可能需要數組的淺拷貝,這就是問題發生的地方。

您可以在使用之前使用 lodash 創建 state 數組的深層副本,這不會導致您的問題:

https://codesandbox.io/s/great-babbage-lorlm

我發現出了什么問題。 我會發布一個答案,以防萬一有人在遇到同樣的問題時偶然發現這個問題。

在調試模式下,react 將運行某些功能兩次,以阻止某些可能導致錯誤的操作。 其中一項操作是直接修改 state。 做的時候

this.setState(state => {
      //find the joke with the matching id and increase score by one
      const modifiedJokes = state.jokes.map(joke => {
        if (joke.id === id) {
          
          joke.score = joke.score + 1;
          
        }
        return joke;
      });
      console.log(modifiedJokes);
      return { jokes: modifiedJokes };

map function 返回一個新數組,其中每個元素都指向原始數組中的相同元素。 因此通過做


state.jokes.map(joke => {
        if (joke.id === id) {          
          joke.score = joke.score + 1;          
        }

我有效地直接修改了 state。 React 在調試模式下運行 setstate function 兩次以清除這種操作。

所以修改嵌套在數組中的 object 的屬性的正確“反應方式”是這樣做

this.setState(state =>{
   let modifiedJokes = state.jokes.map(joke => {
        
        if (joke.id === id) {          
          return {...joke, score:joke.score+1}         
        }
        else{ return joke}
   })
   return {jokes:modifiedJokes}
}) 

這樣,當遇到具有正確 ID 的元素時,將由該特定元素制作副本,並且該副本的分數增加一,這不會影響仍在 state 中的實際元素保持不變,直到它被反應修改提交新的 state

暫無
暫無

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

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