[英]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.