使用具有复杂对象的挂钩来设置提供者值时无法更新上下文状态
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)}
当我调用 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)}