使用带有复杂对象的钩子设置提供程序值时,无法更新上下文状态

时间:2019-02-11 19:48:08

标签: javascript reactjs react-hooks

当我调用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} />;
};

2 个答案:

答案 0 :(得分:2)

使用以下代码:

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

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

我假设您在这里使用useState来尝试避免在每个渲染中创建一个新对象,因此即使上下文没有变化,也强制重新渲染依赖于上下文的所有对象。为此使用的合适的钩子是useMemo

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

我只将filterSidebarIsOpen放入依赖项数组,因为对于您当前的代码,它是三个可以更改的唯一一个(toggleFilterSidebar是不会更改的状态设置器, filters当前没有设置器,因此无法更改。

答案 1 :(得分:0)

useState希望函数在useState最初执行之后设置值,因此,如果value表示状态,则setValue表示setState ...

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

然后使用setValue对其进行更改

onClick={setValue(newValue)}