在不改变全局状态的情况下过滤组件中的 useContext 状态

Filter useContext state in a component without changing global state

我有一个使用 useContext 检索全局状态的组件,它是 movies/TV 节目的列表。我试图将这个全局状态保存到本地状态,这样我就可以在单击按钮时按媒体类型(电影或电视节目)过滤列表,但过滤器应该只反映在本地,而不是调度一个动作来改变全局状态(我不想丢失完整的列表)。

但是,将全局状态存储到局部状态后,局部状态为空。这是组件的代码:

import React, { useContext, useState, useEffect } from "react";

import { WatchListContext } from "../../contexts/WatchListProvider";

import WatchItem from "../WatchItem";

const WatchList = () => {
  const { state } = useContext(WatchListContext);
  const [watchList, setWatchList] = useState(state);
  const [filter, setFilter] = useState("");

  useEffect(() => {
    setWatchList((previousWatchlist) => {
      const filteredWatchList = previousWatchlist.filter(
        (watchItem) => watchItem.media_type === filter
      );

      return filteredWatchList;
    });
  }, [filter]);

  return (
    <div>
      <div>
        <button onClick={() => setFilter("tv")}>TV</button>
        <button onClick={() => setFilter("movie")}>MOVIES</button>
      </div>

      {watchList
        .filter((watchItem) => watchItem.media_type === filter)
        .map(({ id, title, overview, poster_url, release_date, genres }) => (
          <WatchItem
            key={id}
            title={title}
            overview={overview}
            poster_url={poster_url}
            release_date={release_date}
            genres={genres}
          />
        ))}
    </div>
  );
};

export default WatchList;

我不明白为什么这不起作用。任何帮助将不胜感激!

您不能像 (const [watchList, setWatchList] = useState(state);) 那样直接将 global statelocal state 联系起来:-

  • 通过这样做,它会自动与你在 context 中声明的 statedefault 值联系起来,它总是一个 array[] 。所以要解决这个问题,你为什么不 trackstate 的传入 更改 useEffect,像这样:-

  • WatchList.js:-

import React, { useContext, useState, useEffect } from "react";

import { WatchListContext } from "../../contexts/WatchListProvider";

import WatchItem from "../WatchItem";

const WatchList = () => {
  const { state } = useContext(WatchListContext);
  const [watchList, setWatchList] = useState([]);
  const [filter, setFilter] = useState("");

  // handle fetching current changes of state received by Context
  useEffect(() => {
    (() => setWatchList(state))()
  }, [state])  

  // handle filtering of data
  useEffect(() => {
    setWatchList((previousWatchlist) => {
      const filteredWatchList = previousWatchlist.filter(
        (watchItem) => watchItem.media_type === filter
      );

      return filteredWatchList;
    });
  }, [filter]);

  return (
    <div>
      <div>
        <button onClick={() => setFilter("tv")}>TV</button>
        <button onClick={() => setFilter("movie")}>MOVIES</button>
      </div>

      {watchList
        .filter((watchItem) => watchItem.media_type === filter)
        .map(({ id, title, overview, poster_url, release_date, genres }) => (
          <WatchItem
            key={id}
            title={title}
            overview={overview}
            poster_url={poster_url}
            release_date={release_date}
            genres={genres}
          />
        ))}
    </div>
  );
};

export default WatchList;