简体   繁体   English

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

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

When I call toggleFilterSidebar it should toggle the state of filterSidebarIsOpen from false to true and vice versa but onClick nothing happens, but when I pass the Provider value directly as an object it works. 当我调用toggleFilterSidebar ,应该将toggleFilterSidebar的状态从false切换为true,反之亦然,但是onClick不会发生任何事情,但是当我直接将Provider值作为对象传递时,它就可以工作。

Why does this work? 为什么这样做?

1). 1)。

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

and this doesnt 而且这不

2). 2)。

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

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

My Code 我的密码

FilterSidebar.context.js 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 FilterButton.js

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

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

With this code: 使用此代码:

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

you are providing useState with an initial value which is only used when the component is first mounted. 您正在为useState提供一个初始值,该初始值仅在首次安装组件时使用。 It will not be possible for value to ever change since you aren't even creating a variable for the setter (eg const [value, setValue] = useState(...) ). 因为您甚至都没有为setter创建变量(例如const [value, setValue] = useState(...)const [value, setValue] = useState(...)所以value永远都不可能改变。

I assume you are using useState here to try to avoid a new object being created with each render and thus forcing a re-render of everything dependent on the context even if it didn't change. 我假设您在这里使用useState来尝试避免在每个渲染过程中创建一个新对象,从而迫使重新渲染依赖于上下文的所有内容,即使它没有更改也是如此。 The appropriate hook to use for this purpose is useMemo : 用于此目的的合适钩子是useMemo

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

I've only put filterSidebarIsOpen into the dependencies array, because with your current code it is the only one of the three that can change ( toggleFilterSidebar is a state setter which won't change, filters doesn't currently have a setter so it can't change). 我只将filterSidebarIsOpen放入依赖项数组,因为使用您当前的代码,它是可以更改的三个中的唯一一个( toggleFilterSidebar是不会更改的状态设置器, filters当前没有设置器,因此它可以不变)。

useState expects a function to set the value after useState initially does, so if value represents state, setValue would represent setState... useState希望函数在useState最初设置之后设置值,因此如果value表示状态,则setValue表示setState ...

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

then use setValue to change it 然后使用setValue进行更改

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM