繁体   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