【问题标题】:UseReduce Hook dispatch twice-ReactJSUseReducer Hook dispatch 两次——React JS
【发布时间】:2020-05-09 05:18:05
【问题描述】:

我开发了一个小应用程序,目的是研究 React Hooks。该应用程序包括在一个部分中写入艺术家的姓名。在下一部分,一个类似的表格,用于填写每个艺术家的专辑。

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

有趣的是,第一次点击时,我只经过一次,但第二次看到我选择了两次调度艺术家。

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

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;
  }
};

【问题讨论】:

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


    【解决方案1】:

    这里有两件事你需要考虑

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

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

    • 类组件构造函数、渲染和 shouldComponentUpdate 方法
    • 类组件静态getDerivedStateFromProps方法
    • 函数组件体
    • 状态更新函数(setState 的第一个参数)
    • 传递给 useState、useMemo 或 useReducer 的函数
    • 其次,您没有为艺术家附加任何专辑,因此每张专辑的 Artist_creator 始终为空,当您尝试根据它进行过滤时,将返回一个空数组
    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( 专辑 => 专辑.artist_creator === action.payload ) // 从所有专辑中过滤的选定专辑的不同键 };

    【讨论】:

    • 感谢您的回答。关于你的第二个意见。如果我这样做,如果您查看 Github 链接,在创建专辑的组件 (Albums.js) 中创建包含艺术家 ID 的新专辑。如果您查看专辑缩减器,我定义了 selectedartist 状态,即创建新专辑时附加的状态。
    猜你喜欢
    • 2020-07-19
    • 2020-01-27
    • 2019-07-30
    • 1970-01-01
    • 2020-02-25
    • 2020-04-13
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多