使用具有复杂对象的挂钩来设置提供者值时无法更新上下文状态

cant update context state when using hooks with a complex object to set providers value

当我调用 toggleFilterSidebar 时,它应该将 filterSidebarIsOpen 的状态从 false 切换为 true,反之亦然,但是 onClick 没有任何反应,但是当我直接将 Provider 值作为对象传递时它起作用了。

为什么这样做?

1).

return <FilterSidebarContext.Provider value={{
    toggleFilterSidebar,
    filterSidebarIsOpen,
    filters,
  }}>{children}</FilterSidebarContext.Provider>;

而这不是

2).

  const [value] = useState({
    toggleFilterSidebar,
    filterSidebarIsOpen,
    filters,
  });

  return <FilterSidebarContext.Provider value={value}>{children}</FilterSidebarContext.Provider>;

我的代码

FilterSidebar.context.js

import React, { useState } from 'react';

export const FilterSidebarContext = React.createContext({});

export const FilterSidebarProvider = ({ children }) => {
  const [filterSidebarIsOpen, setFilterSidebarIsOpen] = useState(true);
  const toggleFilterSidebar = () => setFilterSidebarIsOpen(!filterSidebarIsOpen);
  const [filters] = useState({ regions: [] });

  const [value] = useState({
    toggleFilterSidebar,
    filterSidebarIsOpen,
    filters,
  });

  return <FilterSidebarContext.Provider value={value}>{children}</FilterSidebarContext.Provider>;
};

export const FilterSidebarConsumer = FilterSidebarContext.Consumer;
export default FilterSidebarContext;

FilterButton.js

const FilterButton = ({ className, getTotalActiveFilters }) => {
  const { toggleFilterSidebar, filterSidebarIsOpen } = useContext(FilterSidebarContext);

  return <Button className={cx({ [active]: filterSidebarIsOpen })} onClick={toggleFilterSidebar} />;
};

使用此代码:

  const [value] = useState({
    toggleFilterSidebar,
    filterSidebarIsOpen,
    filters,
  });

您正在为 useState 提供一个初始值,该值仅在首次安装组件时使用。 value 不可能改变,因为您甚至没有为 setter 创建变量(例如 const [value, setValue] = useState(...))。

我假设您在这里使用 useState 来尝试避免每次渲染都创建一个新对象,从而强制重新渲染依赖于上下文的所有内容,即使它没有改变。用于此目的的适当挂钩是 useMemo:

  const value = useMemo(()=>({
    toggleFilterSidebar,
    filterSidebarIsOpen,
    filters
  })[filterSidebarIsOpen]);

我只将 filterSidebarIsOpen 放入 dependencies 数组,因为对于您当前的代码,它是三个可以更改的唯一一个(toggleFilterSidebar 是一个状态 setter这不会改变,filters 目前没有 setter 所以它不能改变)。

useState 期望函数在 useState 最初设置值之后设置值,因此如果值表示状态,setValue 将表示 setState...

const [value, setValue] = useState(initialValue);

然后用setValue来改变它

onClick={() => setValue(newValue)}