이 게시물에서는 useState 후크 React 앱에서 클로저를 생성하는 방법을 보여드리겠습니다.
클로저가 무엇인지 설명하지 않겠습니다. 이 주제에 대한 리소스가 많고 반복하고 싶지 않기 때문입니다. @imranabdulmalik의 이 기사를 읽어보시길 권합니다.
간단히 말하면, 클로저는 (Mozilla에서):
... 주변 상태(어휘 환경)에 대한 참조와 함께 묶인(동봉된) 함수의 조합입니다. 즉, 클로저를 사용하면 내부 함수에서 외부 함수 범위에 액세스할 수 있습니다. JavaScript에서는 함수가 생성될 때마다 함수 생성 시간.
에 클로저가 생성됩니다.어휘적 환경이라는 용어에 익숙하지 않은 경우를 대비해 @soumyadey 또는 이 글을 읽어보세요.
React 애플리케이션에서는 useState 후크로 생성된 구성 요소 상태에 속하는 변수의 클로저를 실수로 생성할 수 있습니다. 이런 일이 발생하면 오래된 클로저 문제에 직면하게 됩니다. 즉, 그 동안 변경되어 더 관련성이 없는 상태의 이전 값을 참조할 때입니다.
저는 setTimeout 메소드 콜백의 클로저에서 닫힐 수 있는 카운터(상태에 속함)를 증가시키는 것이 주요 목표인 Demo React 애플리케이션을 만들었습니다.
간단히 말하면 이 앱은 다음을 수행할 수 있습니다.
다음 그림에서는 카운터가 0인 앱의 초기 UI 상태를 보여줍니다.
카운터 폐쇄를 세 단계로 시뮬레이션합니다.
5초 후 카운터 값은 2입니다.
카운터의 예상 값은 12여야 하지만 2를 얻습니다.
이런 일이 발생하는 이유는 setTimeout에 전달된 콜백에서 카운터 폐쇄를 생성했고 시간 초과가 트리거될 때 카운터를 다음부터 설정하기 때문입니다. 이전 값(1).
setTimeout(() => { setLogs((l) => [...l, `You closed counter with value: ${counter}\n and now I'll increment by one. Check the state`]) setTimeoutInProgress(false) setStartTimeout(false) setCounter(counter 1) setLogs((l) => [...l, `Did you create a closure of counter?`]) }, timeOutInSeconds * 1000);
앱 구성 요소의 전체 코드를 따릅니다.
function App() { const [counter, setCounter] = useState(0) const timeOutInSeconds: number = 5 const [startTimeout, setStartTimeout] = useState (false) const [timeoutInProgress, setTimeoutInProgress] = useState (false) const [logs, setLogs] = useState >([]) useEffect(() => { if (startTimeout && !timeoutInProgress) { setTimeoutInProgress(true) setLogs((l) => [...l, `Timeout scheduled in ${timeOutInSeconds} seconds`]) setTimeout(() => { setLogs((l) => [...l, `You closed counter with value: ${counter}\n and now I'll increment by one. Check the state`]) setTimeoutInProgress(false) setStartTimeout(false) setCounter(counter 1) setLogs((l) => [...l, `Did you create a closure of counter?`]) }, timeOutInSeconds * 1000); } }, [counter, startTimeout, timeoutInProgress]) function renderLogs(): React.ReactNode { const listItems = logs.map((log, index) => {log} ); return{listItems}
; } function updateCounter(value: number) { setCounter(value) setLogs([...logs, `The value of counter is now ${value}`]) } function reset() { setCounter(0) setLogs(["reset done!"]) } return (); } export default App;Closure demo
Counter value: {counter}
Follow the istructions to create a closure of the state variable counter
- Set the counter to preferred value
- Start a timeout and wait for {timeOutInSeconds} to increment the counter (current value is {counter})
- Increment by 10 the counter before the timeout
{ renderLogs() }
이 솔루션은 렌더링에 필요하지 않은 값을 참조할 수 있는 useRef 후크 사용을 기반으로 합니다.
따라서 App 구성 요소에 다음을 추가합니다.
const currentCounter = useRef(counter)
그런 다음 아래와 같이 setTimeout의 콜백을 수정합니다.
setTimeout(() => { setLogs((l) => [...l, `You closed counter with value: ${currentCounter.current}\n and now I'll increment by one. Check the state`]) setTimeoutInProgress(false) setStartTimeout(false) setCounter(currentCounter.current 1) setLogs((l) => [...l, `Did you create a closure of counter?`]) }, timeOutInSeconds * 1000);
현재 값을 증가시키기 전에 기록하므로 콜백은 카운터 값을 읽어야 합니다.
값을 읽을 필요가 없는 경우 기능 표기를 사용하여 카운터를 업데이트하면 카운터가 닫히는 것을 방지할 수 있습니다.
seCounter(c => c 1)
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3