为什么即使在React中有使用钩子的e.preventDefault,onClick事件也会触发两次?

问题描述

更新:问题直接出在减速器上,与onClick函数或deleteLastItem函数无关。我用console.logs进行了测试,显然唯一重复两次的就是直接在化简器中的那个。

我同时测试了useReducer和useContext这两个钩子,因为我认为它们可以很好地协同工作,但是显然,当我将一个函数设置为onClick函数时,它会被触发两次,而根本就不会t,因为我要从数组中删除最后一项,所以它删除了两项而不是一项。

这是存储上下文和reducer挂钩的文件

import React,{createContext,useReducer} from "react";

const initialState = {
  books: [
    {name: "Book 8",autor: "Author 8",id: 8},{name: "Book 7",autor: "Author 7",id: 7},{name: "Book 6",autor: "Author 6",id: 6},{name: "Book 5",autor: "Author 5",id: 5},{name: "Book 4",autor: "Author 4",id: 4},{name: "Book 3",autor: "Author 3",id: 3}
  ]
}

const reducer = (state,action) => {
  switch (action.type) {
    case "DELETE":
      state.books.pop();
      console.log("hey");
      return {...state}
    default:
      return {...state}
  }
}

export const BookContext = createContext();

export const BookProvider = props => {
  const [state,dispatch] = useReducer(reducer,initialState);

  // Actions
  const deleteLastBook = () => dispatch({type: "DELETE"});

  return (
    <BookContext.Provider value={{books: state.books,deleteLastBook}}>
      {props.children}
    </BookContext.Provider>
  )
}

您可以看到console.log("hey")是什么,它告诉我它被执行了两次(而不是一次看到屏幕上的项目被擦除了两次)

以下是引入上下文和发生问题的组件:

import React,{useContext} from 'react';
import {BookContext} from "../context/BookContext";

const Books = () => {

  const information = useContext(BookContext);

  const {books,deleteLastBook} = information;

  const deleteBook = e => {
    e.preventDefault();
    deleteLastBook();
  };

  return (
    <div>
      {console.log(books)}
      {books.map(book => (<h1 key={book.id}>{book.name}</h1>))}
      <button onClick={deleteBook}>Delete book</button>
    </div>
  )
}

export default Books;

最后,这是app.js,我认为它不会有用,但以防万一:

import React from 'react';
import './App.css';
import {BookProvider} from "./context/BookContext";
import Books from "./components/Books";

const App = () => {
  return (
    <BookProvider>
      <div className="App">
        <Books />
      </div>
    </BookProvider>
  );
}

export default App;

解决方法

解决此问题的方法如下,我使用filter方法更改了reducer return语句,它起作用了:

const reducer = (state,action) => {
  switch (action.type) {
    case "DELETE":
      const lastItem = state.books[state.books.length - 1];
      return {
        ...state,books: state.books.filter(book => book !== lastItem)
      }
    default:
      return {...state}
  }
}