React hooks-setState没有更新状态属性以显示侧边栏



我有一个事件,当你调整窗口大小时,会显示桌面侧边栏或移动侧边栏。如果窗口小于,但有一些变量不会立即更新以显示侧边栏,如果我在桌面窗口中,我可以使用类

我创建了一个沙盒https://codesandbox.io/s/sidebar-hooks-8oefi为了查看代码,我在App_class.js中有一个类组件,如果我在App中替换它,它就可以工作,但使用钩子(App_hooks.js文件,默认情况下在App.js中),我无法使它工作

感谢您的关注。我期待着你的答复。

在课堂上,我可以使用

if (isMobile !== wasMobile) {
this.setState({
isOpen: !isMobile
});
}
const App = props => {
//minicomponent to update width
const useListenResize = () => {
const [isOpen, setOpen] = useState(false);
const [isMobile, setMobile] = useState(true);
//const [previousWidth, setPreviousWidth] = useState( -1 );
let previousWidth = -1;
const updateWidth = () => {
const width = window.innerWidth;
const widthLimit = 576;
let newValueMobile = width <= widthLimit;
setMobile(isMobile => newValueMobile);
const wasMobile = previousWidth <= widthLimit;
if (isMobile !== wasMobile) {
setOpen(isOpen => !isMobile);
}
//setPreviousWidth( width );
previousWidth = width;
};
useEffect(() => {
updateWidth();
window.addEventListener("resize", updateWidth);
return () => {
window.removeEventListener("resize", updateWidth);
};
// eslint-disable-next-line
}, []);
return isOpen;
};
const [isOpen, setOpen] = useState(useListenResize());
const toggle = () => {
setOpen(!isOpen);
};
return (
<div className="App wrapper">
<SideBar toggle={toggle} isOpen={isOpen} />
<Container fluid className={classNames("content", { "is-open": isOpen })}>
<Dashboard toggle={toggle} isOpen={isOpen} />
</Container>
</div>
);
};
export default App;

使用setState不起作用

问题是在此处设置isMobile值之后,

setMobile(isMobile => newValueMobile);

,您立即引用了该值

if (isMobile !== wasMobile) {
setOpen(isOpen => !isMobile);
}

由于setStateasync性质,您一直在这里获得isMobile的先前值。

要实现这一点,您需要对代码进行一些更改。

您正在直接更改previousWidth的值,您应该使previousWidth处于一种状态,并使用setter函数来更改值。

const [previousWidth, setPreviousWidth] = useState(-1);
setPreviousWidth(width);  //setter function

不能在setState之后立即获取值。您应该使用另一个具有isMobilepreviousWidthuseEffect作为依赖数组。

useEffect(() => {
const wasMobile = previousWidth <= widthLimit;
if (isMobile !== wasMobile) {
setOpen(isOpen => !isMobile);
}
}, [isMobile, previousWidth]);

演示

由于updateWidth在组件装载上使用useEffect注册一次,因此它将引用一个过时的状态(isMobile),该状态始终为true,因此setOpen(isOpen => !isMobile)永远不会工作。

编辑:以下代码说明了您的问题的一个更简单的版本:

const Counter = () => {
const [count, setCount] = useState(0)
const logCount = () => {
console.log(count);
}
useEffect(() => {
window.addEventListener('resize', logCount);
}, [])
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
)
}

如果您运行此代码,您会注意到,即使您通过单击按钮更改count的值,在调整浏览器大小时(检查控制台),您也将始终获得初始值,这是因为logCount指的是在定义时获得的状态。

@ravibagul91答案有效,因为它从useEffect访问状态,而不是从事件处理程序访问状态。

你可能想检查一下:React钩子与事件监听器的行为,以及为什么我在函数中看到过时的道具或状态?,它会让你更好地了解发生了什么。

最新更新