Почему событие onClick запускается дважды, хотя в React есть e.preventDefault, использующий хуки?

Обновление: проблема находится непосредственно в редюсере и не имеет ничего общего ни с функцией onClick, ни с функцией deleteLastItem. Я проверил это с помощью console.logs, и, по-видимому, дважды повторяется только тот, который находится непосредственно в редюсере.

Я тестировал хуки useReducer и useContext одновременно, потому что думал, что они могут очень хорошо работать вместе, но, видимо, когда я устанавливаю функцию в функцию onClick, она срабатывает дважды, и важно, что это не так, потому что я Я удаляю последний элемент из массива, поэтому он удаляет два элемента вместо одного.

Вот файл, в котором хранятся контекст и хуки редуктора:

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;

person Guillermo    schedule 06.09.2020    source источник
comment
Попробуйте использовать stopPropagation: stackoverflow.com /вопросы/36316846/   -  person gtamborero    schedule 07.09.2020
comment
Это тоже не @gtamborero   -  person Guillermo    schedule 07.09.2020
comment
Не уверены, есть ли у вас форма вокруг этой кнопки, может быть, просто добавьте type="button" к кнопке, чтобы увидеть, не отправляет ли она где-нибудь форму?   -  person Dominik    schedule 07.09.2020
comment
У меня нет, и это тоже не работает :( @Dominik   -  person Guillermo    schedule 07.09.2020
comment
Когда вы добавите console.log в свою функцию deleteBook, будет ли консоль дважды регистрировать ее?   -  person Dominik    schedule 07.09.2020
comment
Бинго!, это происходит только один раз. Значит проблема в редукторе. Действительно хороший улов, вы знаете, как это исправить? @Доминик   -  person Guillermo    schedule 07.09.2020
comment
Обновление: проблема непосредственно в редьюсере, а не в функции, которая выполняет его в контексте (deleteLastBook), потому что я экспортировал редьюсер напрямую (функция отправки) в контексте в компонент, и он делает то же самое.   -  person Guillermo    schedule 07.09.2020
comment
Я вообще не использую redux или useReducer ни в одном из наших проектов, поэтому я не знаю, что это может быть. Обязательно поделитесь своими выводами и добавьте их в качестве ответа, если никто другой не ответит на этот вопрос.   -  person Dominik    schedule 07.09.2020
comment
@Dominik, хорошо, только что добавил, спасибо за помощь, и если вы придумаете решение, не забудьте сказать мне :)   -  person Guillermo    schedule 07.09.2020


Ответы (1)


Решение этого было следующим, я изменил оператор возврата редуктора, используя метод фильтра, и это сработало:

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}
  }
}
person Guillermo    schedule 06.09.2020