[英]React hooks - setState is not updating the state properties to show sidebar
当您调整 window 的大小时,我有一个事件将显示桌面侧边栏或移动侧边栏。 如果 window 小于但是如果我在桌面 window 中,有些变量不会立即更新以显示侧边栏,我可以使用 class
我创建了一个沙箱https://codesandbox.io/s/sidebar-hooks-8oefi来查看代码,我在 App_class.js 中有 class 组件,如果我在 App 中替换它可以工作,但带有钩子 (App_hooks.js)。 js 文件,默认情况下在 App.js 中)我不能让它工作
感谢您的关注。 我期待着您的回复。
使用 class 我可以这样做:
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);
}
由于setState
的async
性质,您总是在这里获得isMobile
的先前值。
要完成这项工作,您需要对代码进行一些更改。
您正在直接改变previousWidth
值,您应该在 state 中有previousWidth
并使用设置器 function 来更改该值。
const [previousWidth, setPreviousWidth] = useState(-1);
setPreviousWidth(width); //setter function
您无法在setState
之后立即获得价值。 您应该使用另一个useEffect
和isMobile
和previousWidth
作为依赖数组。
useEffect(() => {
const wasMobile = previousWidth <= widthLimit;
if (isMobile !== wasMobile) {
setOpen(isOpen => !isMobile);
}
}, [isMobile, previousWidth]);
由于updateWidth
在组件挂载时使用 useEffect 注册一次,因此它将引用过时的 state ( isMobile
),这始终是正确的,因此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
引用了一个 state是在定义的那一刻获得的。
@ravibagul91 答案有效,因为它从 useEffect 访问useEffect
,而不是从事件处理程序访问。
您可能想检查: React hooks behavior with event listener和Why am I see stale props or state inside my function? ,它会让您更好地了解正在发生的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.