UseReduce Hook отправляет дважды -ReactJS

Я разрабатываю небольшое приложение с целью изучения перехватчиков реакции. Приложение состоит из написания имени исполнителя в разделе. В следующем разделе аналогичная форма для заполнения альбомов каждого исполнителя.

У меня отдельные компоненты, а также контекст, статус и редуктор. У меня есть отдельный контекст для каждого исполнителя, альбомов и песен. Когда я нажимаю кнопку исполнителя, я хочу отфильтровать альбомы, чтобы отображались только их альбомы. Но используйте диспетчер редуктора дважды, и в журнале консоли он сообщает мне, что оба исходят из файла редуктора.

Интересно то, что когда я щелкаю в первый раз, я прохожу только один раз, а во второй раз вижу, что дважды выбираю исполнителя отправки.

Еще одна интересная вещь заключается в том, что когда я меняю выбранного исполнителя, он удаляет альбомы состояния, в которых у меня есть все альбомы. Он не фильтрует их, а удаляет.

Репозиторий GitHub

Это форма, в которой я нажимаю, чтобы вызвать идентификатор каждого исполнителя, и отправляю текущего выбранного исполнителя в контекст исполнителя и контекст альбома.

import React, { useContext } from "react";

import AlbumContext from "../../context/Album/AlbumContext";
import ArtistContext from "../../context/Artist/ArtistContext";

const Artist = ({ item }) => {
  const albumContext = useContext(AlbumContext);
  const { getArtist } = albumContext;

  const artistContext = useContext(ArtistContext);
  const { artist, getselectedArtist } = artistContext;

  const handleSelect = (artist_id) => {
    getArtist(artist_id);
    getselectedArtist(artist_id);
  };
  return (
    <>
      <div
        style={{ border: "1px solid black", margin: "10px", padding: "5px" }}
      >
        <p>{item.name}</p>
        <button type="button">Edit</button>
        <button type="button">Delete</button>
        <button type="button" onClick={() => handleSelect(item.id)}>
          Select
        </button>
      </div>
    </>
  );
};

export default Artist;

Второй - ALBUMSTATE, где я вызываю функцию getArtist для отправки и получения всех альбомов этого выбранного исполнителя.

import React, { useReducer } from "react";

import AlbumContext from "./AlbumContext";
import AlbumReducer from "./AlbumReducer";
import { GET_ARTIST, ADD_ALBUM, VALIDATE_FORM } from "../../types";

const AlbumState = (props) => {
  const initialState = {
    albums: [],
    errorform: false,
    selectedartist: "",
  };

  const [state, dispatch] = useReducer(AlbumReducer, initialState);

  //-----METHODS-----//
  const addAlbum = (album) => {
    dispatch({
      type: ADD_ALBUM,
      payload: album,
    });
  };

  const setError = (error) => {
    dispatch({
      type: VALIDATE_FORM,
      payload: error,
    });
  };

  const getArtist = (id) => {
    dispatch({
      type: GET_ARTIST,
      payload: id,
    });
  };

  return (
    <AlbumContext.Provider
      value={{
        selectedartist: state.selectedartist,
        albums: state.albums,
        errorform: state.errorform,
        addAlbum,
        setError,
        getArtist,
      }}
    >
      {props.children}
    </AlbumContext.Provider>
  );
};

export default AlbumState;

Это ALBUMREDUCER

import { GET_ARTIST, ADD_ALBUM, VALIDATE_FORM } from "../../types";

export default (state, action) => {
  switch (action.type) {
    case ADD_ALBUM:
      return {
        ...state,
        albums: [action.payload, ...state.albums],
      };
    case VALIDATE_FORM:
      return {
        ...state,
        errorform: action.payload,
      };
    case GET_ARTIST:
      console.log(action.payload);
      return {
        ...state,
        selectedartist: action.payload,
        albums: state.albums.filter(
          (album) => album.artist_creator === action.payload
        ),
      };

      return {
        ...state,
        selectedartist: action.payload,
      };

    default:
      return state;
  }
};

1 ответ

Решение

Здесь нужно учесть две вещи

  • Вы используете React.strictMode, в котором во время разработки React намеренно дважды вызывает метод отправки. Согласно реагирующим документам

Строгий режим не может автоматически обнаруживать побочные эффекты, но он может помочь вам обнаружить их, сделав их более детерминированными. Это делается путем намеренного двойного вызова следующих функций:

  • Конструктор компонентов класса, методы рендеринга и shouldComponentUpdate
  • Статический метод getDerivedStateFromProps компонента класса
  • Тела функциональных компонентов
  • Функции средства обновления состояния (первый аргумент setState)
  • Функции, переданные в useState, useMemo или useReducer
  • Во-вторых, вы не прикрепляете никаких альбомов с исполнителем, поэтому ваш artist_creator для каждого альбома всегда имеет значение null, и когда вы пытаетесь выполнить фильтрацию на его основе, вернет пустой массив
case GET_ARTIST:
      console.log(action.payload, state.albums, "getArtistalbum");
      return {
        ...state,
        selectedartist: action.payload,
        albums: state.albums.filter(
          album => album.artist_creator === action.payload
        ) // This returns empty array
      };

  • Последнее, что следует отметить, это то, что вы заменяете исходный массив альбомов в редукции отфильтрованным, и, следовательно, все данные ваших альбомов будут удалены. Вместо этого сохраните отдельный ключ для отфильтрованных элементов и отфильтруйте его как

    case GET_ARTIST: console.log(action.payload, state.albums, "getArtistalbum"); return { ...state, selectedartist: action.payload, selectedAlbums: state.albums.filter( album => album.artist_creator === action.payload) // Другой ключ для выбранных альбомов отфильтрован из всех альбомов};

Другие вопросы по тегам