[英]Reactjs: Why doesn't state boolean lock on event listener?
React Noob - 在我花幾個小時挖掘之前,我想我會在這里問一個快速的答案。
在下面的示例中,我在 useEffect 中有一個事件偵聽器,它偵聽容器上的滾動 position 並在某個點之后觸發一個觸發器,如果它還沒有這樣做的話。
我想知道為什么即使 boolean 在 DOM 中注冊為 true,事件仍會觸發。 我已經通過使用普通變量解決了這個問題,但我認為理解為什么會發生這種情況會讓我受益。 我已經仔細閱讀了變異狀態,並嘗試將 useState 更改為 object ,例如 useState({status: false}) 但這有類似的結果。
即使指向閱讀主題的方向也足夠了。 干杯!
const App = (props) => { var [stateBool, setStateBool] = React.useState(false); var nonStateBool = false; var containerRef = React.useRef(null); React.useEffect(() => { containerRef.current.addEventListener('scroll', (event) => { var cont = containerRef.current; var triggerPoint = cont.scrollWidth - cont.clientWidth - cont.scrollWidth * 0.2; var scrollPos = cont.scrollLeft; var triggerEl = document.getElementById('vr'); if (triggerEl) { triggerEl.style.left = triggerPoint + 'px'; } if (scrollPos > triggerPoint && stateBool === false) { console.log('triggered', nonStateBool, stateBool); setStateBool(true); } }); }, [containerRef.current, stateBool]); return ( <div> <div ref={containerRef} id='container'> <div className='divElement'> inner element <vr id='vr'></vr> </div> </div> <ul> <li> nonStateBool {nonStateBool? 'true': 'false'}</li> <li> State Bool {stateBool? 'true': 'false'}</li> </ul> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
#container { width: 200px; background: grey; padding: 1em; overflow: hidden; overflow-x: scroll; }.divElement { width: 1500px; height: 50px; background: red; }.divElement vr { border: 1px solid white; position: relative; height: 100%; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>
你有:
React.useEffect(() => {
containerRef.current.addEventListener('scroll', (event) => {
// ...
});
}, [containerRef.current, stateBool]);
因此,每次stateBool
更改時,您都會調用addEventListener
- 添加一個新的滾動處理程序。 對於您期望的更可預測的 output,請在效果清理中刪除先前的滾動處理程序。
React.useEffect(() => {
const handler = (event) => {
// ...
};
containerRef.current.addEventListener('scroll', handler);
return () => containerRef.current.removeEventListener('scroll', handler);
}, [containerRef.current, stateBool]);
const App = (props) => { var [stateBool, setStateBool] = React.useState(false); var nonStateBool = false; var containerRef = React.useRef(null); React.useEffect(() => { const handler = (event) => { var cont = containerRef.current; var triggerPoint = cont.scrollWidth - cont.clientWidth - cont.scrollWidth * 0.2; var scrollPos = cont.scrollLeft; var triggerEl = document.getElementById('vr'); if (triggerEl) { triggerEl.style.left = triggerPoint + 'px'; } if (scrollPos > triggerPoint && stateBool === false) { console.log('triggered', nonStateBool, stateBool); setStateBool(true); } }; containerRef.current.addEventListener('scroll', handler); return () => containerRef.current.removeEventListener('scroll', handler); }, [containerRef.current, stateBool]); return ( <div> <div ref={containerRef} id='container'> <div className='divElement'> inner element <vr id='vr'></vr> </div> </div> <ul> <li> nonStateBool {nonStateBool? 'true': 'false'}</li> <li> State Bool {stateBool? 'true': 'false'}</li> </ul> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
#container { width: 200px; background: grey; padding: 1em; overflow: hidden; overflow-x: scroll; }.divElement { width: 1500px; height: 50px; background: red; }.divElement vr { border: 1px solid white; position: relative; height: 100%; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>
但是,更好的方法是使用容器的onScroll
——當沒有合理的方法通過 React 獲得相同的結果時,最好只使用像addEventListener
這樣的 vanilla DOM 方法。
const App = (props) => { var [stateBool, setStateBool] = React.useState(false); var nonStateBool = false; var containerRef = React.useRef(null); const scrollHandler = (event) => { var cont = containerRef.current; var triggerPoint = cont.scrollWidth - cont.clientWidth - cont.scrollWidth * 0.2; var scrollPos = cont.scrollLeft; var triggerEl = document.getElementById('vr'); if (triggerEl) { triggerEl.style.left = triggerPoint + 'px'; } if (scrollPos > triggerPoint && stateBool === false) { console.log('triggered', nonStateBool, stateBool); setStateBool(true); } }; return ( <div> <div ref={containerRef} onScroll={scrollHandler} id='container'> <div className='divElement'> inner element <vr id='vr'></vr> </div> </div> <ul> <li> nonStateBool {nonStateBool? 'true': 'false'}</li> <li> State Bool {stateBool? 'true': 'false'}</li> </ul> </div> ); }; ReactDOM.render(<App />, document.getElementById('root'));
#container { width: 200px; background: grey; padding: 1em; overflow: hidden; overflow-x: scroll; }.divElement { width: 1500px; height: 50px; background: red; }.divElement vr { border: 1px solid white; position: relative; height: 100%; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.