如何正确声明箭头函数?

3

什么是区别

document.addEventListener("click", (e) => handleClick(e));

并且

document.addEventListener("click", handleClick);

在第一种情况下,我在控制台中看到:

console result

在第二种情况下:

console result

那么为什么有时结果会重复出现?

这段代码片段:

import React, {useState, useEffect} from 'react'
import TodoList from './TodoList'

export default function App () {

  const [todos, setTodos] = useState([]);
  const [todoTitle, setTodoTitle] = useState("");
  const [changed, setChanged] = useState(false);

  const handleClick = (e) => console.log("click", e.target);

  useEffect(() => {
    const raw = localStorage.getItem("todos") || JSON.stringify([]);
    setTodos(JSON.parse(raw));
  }, []);

  useEffect(() => {
    document.addEventListener("click", (e) => handleClick(e));
    localStorage.setItem("todos", JSON.stringify(todos));
    
    return () => {
      document.removeEventListener("click", (e) => handleClick(e));
    }
  })

  const addTodo = event => {
    if (event.key === "Enter") {
      setTodos([
        ...todos,
        {
          id: Date.now(),
          title: todoTitle,
          completed: false
        }
      ])
      setTodoTitle("");
    }
  }
    return (
      <div className="container">
        <h1>Todo app</h1>
          <div className="input-field">
            <input
              type="text"
              value={todoTitle}
              onChange={e => setTodoTitle(e.target.value)}
              onKeyPress={addTodo}
              />
            <label>Todo name</label>
          </div>
          <TodoList todos={todos} />
          <button onClick = {() => setChanged(!changed)}>button</button>
      </div>
    );
}

取决于 handleClick 是否使用 this - Suraj Rao
@SurajRao:不,这与此无关。如果您使用对象方法作为事件处理程序,则更多是一个问题。 - Felix Kling
1个回答

8

主要的区别在于,第一种情况下您直接绑定了handleClick,而在第二种情况下,您绑定了一个“中间”函数来调用handleClick。虽然可观察结果是相同的。

但是,您看到输出翻倍的原因是

document.removeEventListener("click", (e) => handleClick(e));

不起作用。只有当您传递与 addEventListener 中传递的相同函数时,removeEventListener 才能工作。 如果您传递 handleClick,那就没问题了,但是如果您使用“中间”函数,则不可能这样做,因为您没有保留对该函数的引用。

您可以轻松解决此问题:

useEffect(() => {
  const handler = (e) => handleClick(e)
  //    ^^^^^^^ "remember" the function
  document.addEventListener("click", handler);
  //                                 ^^^^^^^
  localStorage.setItem("todos", JSON.stringify(todos));

  return () => {
    document.removeEventListener("click", handler);
    //                                    ^^^^^^^
  }
})

但是这里实际上没有必要使用额外的函数。那个间接层并没有什么用处。直接传递handleClick即可。


所以您的意思是,在添加侦听器时没有区别,但仅在将函数名称传递给“addEventListener”和“removeEventListener”时才可以进行删除? - Anthony
当您在某个地方使用箭头函数时,而不将其存储在变量中,每次编写它时它都有一个新的内存引用。因此,当您将箭头函数传递给removeEventListener时,它是一个新函数,并且不是您传递给addEventListener的相同函数。 - Iman Emadi
太难理解了。这是因为 (e) => handleClick(e) 是对象,而没有相同的对象?但是简单的 handleClick 是对函数的引用? - Anthony
@Anthony:是的。但这并不特定于箭头函数。这适用于任何函数,因为即使它们执行相同的操作,两个函数对象也永远不会相同:console.log(function() { return true; } === function() { return true; }) - Felix Kling
我明白了。最后一个问题是:“主要区别在于,在第一种情况下,您直接绑定handleClick,而在第二种情况下,您绑定了一个“中间”函数来调用handleClick。但是,观察结果是相同的。” 绑定到什么?这两种情况的绑定有所不同吗? - Anthony
@Anthony:如果这样更有意义,您也可以使用“assign”一词。这只是我用来表达将函数与事件关联的术语。 - Felix Kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接