जैसा कि अन्य ने बताया है, समस्या यह है कि useStateकेवल एक बार कहा जाता है (जैसा deps = []कि अंतराल को स्थापित करने के लिए:
React.useEffect(() => {
const timer = window.setInterval(() => {
setTime(time + 1);
}, 1000);
return () => window.clearInterval(timer);
}, []);
फिर, हर बार setIntervalटिक करने के बाद, यह वास्तव में कॉल करेगा setTime(time + 1), लेकिन कॉलबैक (बंद) परिभाषित होने पर timeहमेशा शुरू में इसका मूल्य होगा setInterval।
आप के useStateसेटर के वैकल्पिक रूप का उपयोग कर सकते हैं और जो वास्तविक मूल्य आप सेट करना चाहते हैं (केवल उसी तरह setState) के बजाय कॉलबैक प्रदान कर सकते हैं :
setTime(prevTime => prevTime + 1);
लेकिन मैं आपको अपना स्वयं का useIntervalहुक बनाने के लिए प्रोत्साहित करूंगा ताकि आप DRY कर सकें और अपने कोड को setInterval घोषित रूप से उपयोग करके सरल कर सकें , जैसा कि Dan Abramov ने React Hooks के साथ SetInterval Declarative बनाने में यहां बताया है :
function useInterval(callback, delay) {
const intervalRef = React.useRef();
const callbackRef = React.useRef(callback);
React.useEffect(() => {
callbackRef.current = callback;
}, [callback]);
React.useEffect(() => {
if (typeof delay === 'number') {
intervalRef.current = window.setInterval(() => callbackRef.current(), delay);
return () => window.clearInterval(intervalRef.current);
}
}, [delay]);
return intervalRef;
}
const Clock = () => {
const [time, setTime] = React.useState(0);
const [isPaused, setPaused] = React.useState(false);
const intervalRef = useInterval(() => {
if (time < 10) {
setTime(time + 1);
} else {
window.clearInterval(intervalRef.current);
}
}, isPaused ? null : 1000);
return (<React.Fragment>
<button onClick={ () => setPaused(prevIsPaused => !prevIsPaused) } disabled={ time === 10 }>
{ isPaused ? 'RESUME ⏳' : 'PAUSE 🚧' }
</button>
<p>{ time.toString().padStart(2, '0') }/10 sec.</p>
<p>setInterval { time === 10 ? 'stopped.' : 'running...' }</p>
</React.Fragment>);
}
ReactDOM.render(<Clock />, document.querySelector('#app'));
body,
button {
font-family: monospace;
}
body, p {
margin: 0;
}
p + p {
margin-top: 8px;
}
#app {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
button {
margin: 32px 0;
padding: 8px;
border: 2px solid black;
background: transparent;
cursor: pointer;
border-radius: 2px;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
सरल और क्लीनर कोड का उत्पादन करने के अलावा, यह आपको स्वचालित रूप से अंतराल को रोकने (और स्पष्ट) की अनुमति delay = nullदेता है और अंतराल आईडी भी लौटाता है, यदि आप इसे स्वयं मैन्युअल रूप से रद्द करना चाहते हैं (जो दान के पदों में शामिल नहीं है)।
वास्तव में, इसमें सुधार भी किया जा सकता है, ताकि यह delayअप्रकाशित होने पर पुनः आरंभ न हो, लेकिन मुझे लगता है कि अधिकांश उपयोग के मामलों के लिए यह काफी अच्छा है।
यदि आप इसके setTimeoutबजाय एक समान उत्तर की तलाश कर रहे हैं setInterval, तो इसे देखें : https://stackoverflow.com/a/59274757/3723993 ।
तुम भी की कथात्मक संस्करण पा सकते हैं setTimeoutऔर setInterval, useTimeoutऔर useInterval, के साथ साथ एक कस्टम useThrottledCallbackहुक में टाइपप्रति में लिखा https://gist.github.com/Danziger/336e75b6675223ad805a88c2dfdcfd4a ।