为什么上下文 api 提供的我的 setter 函数在句柄函数中不起作用

Why is my setter function provided by the context api not working in the handle function

我有这个使用标签的搜索过滤器的实现。

https://codesandbox.io/s/search-filter-tags-zgfcs?file=/src/Tags.tsx:622-626

我一辈子都弄不明白为什么我的 setTags() 方法在 handleChange 函数中不起作用,但在 handleAllChange 函数中却工作正常。

Tags.tsx

import * as React from "react";
import { TagContext } from "./TagContext";

let AllTags = [
  "Html",
  "CSS",
  "JavaScript",
  "ReactJS",
  "GitHub",
  "TypeScript",
  "Celebal"
];

const Tags = () => {
  const { tags, setTags } = React.useContext(TagContext);
  const [allChecked, setAllChecked] = React.useState(false);
  // const [tags, setTags] = React.useState([] as string[]);

  const handleAllChange = () => {
    if (!allChecked) {
      setTags(AllTags);
    } else {
      setTags([]);
    }
    setAllChecked(!allChecked);
  };

  const handleChange = (name: string) => {
    let temp = tags;
    if (temp.includes(name)) {
      temp.splice(temp.indexOf(name), 1);
    } else {
      temp.push(name);
    }
    console.log("temp - ", temp);
    setTags(temp);
  };

  React.useEffect(() => {
    console.log("Tags - ", tags);
  }, [tags]);

  return (
    <>
      <h1>Filter Tags</h1>
      <div className="tags-container">
        <div className="w-fit p-2 m-2">
          <button
            className="p-1 border-2 border-black rounded font-semibold"
            onClick={handleAllChange}
          >
            Apply All
          </button>
        </div>
        {AllTags.map((tag, i) => {
          return (
            <div className="w-fit p-2 m-2" key={i}>
              <input
                className="mt-2"
                type="checkbox"
                value={tag}
                name={tag}
                onChange={(e) => handleChange(tag)}
                checked={tags.includes(tag)}
              />
              <label htmlFor={tag}>#{tag}</label>
            </div>
          );
        })}
      </div>
    </>
  );
};

export default Tags;

标签和 setTags 来自上下文 API。

TagContext.tsx

import * as React from "react";

interface ITagContext {
  tags: any;
  setTags: any;
  handleChange: (name: string) => void;
}

export const TagContext = React.createContext({} as ITagContext);

interface ITagProvider {
  children: React.ReactNode;
}

export const TagProvider = ({ children }: ITagProvider) => {
  const [tags, setTags] = React.useState([] as string[]);

  const handleChange = (name: string) => {
    debugger;
    let tag = name;
    let temp = tags;
    if (temp.includes(tag)) {
      temp.splice(temp.indexOf(tag), 1);
    } else {
      temp.push(tag.toString());
    }
    setTags(temp);
  };

  React.useEffect(() => {
    debugger;
    console.log("Tags in Context - ", tags);
  }, [tags]);
  return (
    <TagContext.Provider value={{ tags, setTags, handleChange }}>
      {children}
    </TagContext.Provider>
  );
};

在您的 handleChange() 函数中,您使用了对 tags 数组的引用:

let temp = tags;

这意味着当您最终调用 setTags(temp); 时,引用没有改变并且您的 Tags 组件无法重新呈现。而是创建一个新数组:

let temp = [...tags];