简体   繁体   中英

React useCallback hook, not receiving updated dependency state value

Below is my simplified version of the problem I'm trying to solve.

Anyone know why my handleKeydown method is not receiving the updated activeTab state variable? I though that because I added activeTab as a dependency, the callback would always receive the updated value. However, that does not seem to be the case.

The callback is called, as expected, every time a key is pressed; However, activeTab is always null , the initial value. Any help is appreciated!

(I've included both a code snippet as well as a jsfiddle link (because the snippet does not seem to be rendering for some reason. The jsfiddle at least renders lol).)

https://jsfiddle.net/Tom904/98veow5b/4/

 const Tabs = () => { const [activeTab, setActiveTab] = React.useState(null); const handleKeydown = React.useCallback(event => { console.log(activeTab); // if a user hits the escape key while a tab is active... if (event.key === 'Escape' && activeTab) { setActiveTab(null); } }, [activeTab]); React.useEffect(() => { window.addEventListener('keydown', handleKeydown); return () => { window.removeEventListener('keydown', handleKeydown); }; }, []); return ( <div> <button onClick={() => setActiveTab('1')}> 1 </button> <button onClick={() => setActiveTab('2')}> 2 </button> <button onClick={() => setActiveTab('3')}> 3 </button> <div> Active tab: {activeTab || 'None'} </div> </div> ) } ReactDOM.render( <Tabs/>, document.getElementById('root') );
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>

The handleKeydown function is updated on every change of activeTab . However the useEffect in which you bind the function to the keydown event is only called on mount. So although the function is recreated, the original instance, with the initial value of activeTab , is called by the event handler.

The useCallback here is redundant, and you can also use functional updates form of useState to avoid the activeTab dependancy:

 const Tabs = () => { const [activeTab, setActiveTab] = React.useState(null); React.useEffect(() => { const handleKeydown = event => { setActiveTab(activeTab => event.key === 'Escape' && activeTab? null: activeTab); }; window.addEventListener('keydown', handleKeydown); return () => { window.removeEventListener('keydown', handleKeydown); }; }, []); return ( <div> <button onClick={() => setActiveTab('1')}> 1 </button> <button onClick={() => setActiveTab('2')}> 2 </button> <button onClick={() => setActiveTab('3')}> 3 </button> <div> Active tab: {activeTab || 'None'} </div> </div> ) } ReactDOM.render( <Tabs/>, document.getElementById('root') );
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM