簡體   English   中英

Reactjs:為什么 state boolean 不鎖定事件偵聽器?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM