UseReduce Hook分派两次-ReactJS

时间:2020-05-09 05:18:05

标签: javascript reactjs react-hooks use-reducer use-context

我开发了一个小应用程序,目的是研究React钩子。该应用程序包括在部分中写上艺术家的名字。在下一节中,将使用类似的表格填充每个艺术家的专辑。

我将所有组件以及上下文,状态和简化器分开。对于每个艺术家,专辑和歌曲,我都有一个单独的上下文。当我单击艺术家按钮时,我想过滤专辑,以便仅出现它们。但是使用reducer调度两次,并在控制台日志中告诉我两者都来自reducer文件。

有趣的是,当我第一次单击时,我只浏览了一次,但是第二次,我看到我两次选择了调度艺术家。

另一个有趣的事情是,当我更改选定的歌手时,它会删除状态专辑,这是我拥有所有专辑的地方。它不会过滤它们,但会删除它们。

GitHub repository

在此表单中,我单击以调用每个艺术家的ID,然后将当前选定的艺术家发送到艺术家上下文和专辑上下文

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 个答案:

答案 0 :(得分:0)

您需要在这里考虑两件事

  • 您正在使用React.strictMode,在开发过程中,React故意两次调用dispatch方法。根据反应文档

严格模式无法自动为您检测副作用,但是 可以使它们更具确定性,从而帮助您发现它们。 这是通过有意重复调用以下功能来完成的:

  • 类组件的构造函数,呈现器和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
      };

  • 最后要注意的是,您正在redux中使用过滤后的原始数组覆盖原始相册数组,因此将删除所有相册数据。而是为过滤的项目保留单独的键,然后像进行过滤一样

    案例GET_ARTIST: console.log(action.payload,state.albums,“ getArtistalbum”); 返回{ ...州, selectedartist:action.payload, selectedAlbums:state.albums.filter( 专辑=> album.artist_creator === action.payload )//从所有专辑中筛选出的所选专辑的其他键 };