React에서 오래된 클로저 피하기
17259 단어 programmingbeginnersreactjavascript
먼저 클로저란 무엇입니까?
JavaScript의 클로저는 내부 함수가 외부 함수를 둘러싸고 나중에 사용할 수 있도록 외부 함수의 변수를 기억하는 경우입니다. 이것은 JavaScript의 어휘 환경 덕분입니다.
하지만 그게 무슨 뜻입니까? 아래 예를 살펴보겠습니다.
const createMultiplier = (multiplyBy) => {
const multiplier = (toMultiply) => {
return multiplyBy * toMultiply;
}
return multiplier;
}
const double = createMultiplier(2);
const ten = double(5);
위의 예에서 클로저를 사용하여 승수 함수를 만들었습니다. 더 설명하자면, multiplier 함수는 함수가 호출될 때를 기억하면서 외부 범위에서 multiplyBy 변수를 둘러쌉니다.
오래된 클로저는 내부 함수가 함수의 오래된 값을 기억하는 경우입니다. 예를 들면 다음과 같습니다.
let a = 0;
const add = () => {
a += 1;
const message = `Variable a is incremented to ${a}`;
return () => {
console.log(message);
}
}
const log = add();
add();
add();
log(); // Outputs 1, Expected output: 3
위의 예에서 0으로 시작하는 숫자 변수를 만든 다음 여기에 1을 더하는 추가 함수를 만듭니다. 하지만 첫 번째 로그를 기록하지 않고 추가 기능을 3번 사용하고 로그할 때 3이 아닌 1을 기록합니다. 왜 그럴까요?
이를 스테일 클로저라고 합니다. 로그 함수는 a 변수의 오래된 버전을 감싸고 현재 있어야 하는 변수 대신 해당 변수를 기록했습니다.
이 문제를 어떻게 해결할까요?
let a = 0;
const add = () => {
a += 1;
return () => {
const message = `Variable a is incremented to ${a}`;
console.log(message);
}
}
const log = add();
add();
add();
log(); // Outputs 3, Expected output: 3
이렇게 하면 로그 함수를 사용할 때 실행할 시간이 되면 현재 a 변수를 둘러싸서 올바른 값을 얻습니다.
여전히 더 많은 정보가 필요한 경우 게시할 때 확인할 수 있는 JavaScript의 클로저에 대한 다른 블로그를 게시할 것입니다.
이제 클로저가 React 코드에 영향을 미칠 수 있습니까? 아래 예를 확인하십시오.
import React, {useState, useEffect} from 'react';
const Timer = () => {
const [time, setTime] = useState(0);
const [isCounting, setIsCounting] = useState(false);
useEffect(() => {
if(isCounting) {
const id = setInterval(() => {
setTime(time + 0.1)
}, 100);
return () => {
clearInterval(id)
}
}
}, [isCounting])
return (
<div>
The time is: {time.toFixed(1)}
<br />
<br />
<button onClick={() => setIsCounting(!isCounting)}>
{isCounting ? "Stop timer" : "Start Timer"}
</button>
</div>
)
}
위의 예는 오래된 클로저입니다. 이유를 알 수 있습니까?
대답이 종속성 배열이라면 정답입니다! 반응 후크는 클로저 개념에 크게 의존하며 타이머가 처음 마운트될 때 시간의 초기 값은 0입니다. 따라서 setInterval의 콜백은 이를 캡처하고 반복해서 업데이트하려고 시도하므로 타이머는 값은 항상 0.1입니다.
어떻게 해결할 수 있습니까? 두 가지 솔루션이 있습니다.
import React, {useState, useEffect} from 'react';
const Timer = () => {
const [time, setTime] = useState(0);
const [isCounting, setIsCounting] = useState(false);
useEffect(() => {
if(isCounting) {
const id = setInterval(() => {
setTime(time + 0.1)
}, 100);
return () => {
clearInterval(id)
}
}
}, [isCounting, time]) // Added time as a dependency
return (
<div>
The time is: {time.toFixed(1)}
<br />
<br />
<button onClick={() => setIsCounting(!isCounting)}>
{isCounting ? "Stop timer" : "Start Timer"}
</button>
</div>
)
}
종속성 배열에 시간을 추가하여 시간이 변경될 때마다 React가 그에 따라 올바른 값으로 함수를 업데이트합니다. 그러나 두 번째 수정 사항이 있습니다.
import React, {useState, useEffect} from 'react';
const Timer = () => {
const [time, setTime] = useState(0);
const [isCounting, setIsCounting] = useState(false);
useEffect(() => {
if(isCounting) {
const id = setInterval(() => {
setTime(time => time + 0.1) // Give the setTime function a callback
}, 100);
return () => {
clearInterval(id)
}
}
}, [isCounting])
return (
<div>
The time is: {time.toFixed(1)}
<br />
<br />
<button onClick={() => setIsCounting(!isCounting)}>
{isCounting ? "Stop timer" : "Start Timer"}
</button>
</div>
)
}
useState 후크에서 set 함수에 콜백을 제공하면 react가 현재 상태에서 자동으로 상태를 업데이트할 수 있습니다. 또한 종속성 배열 안에 넣을 필요가 없습니다. 이는 때때로 혼란을 야기할 수 있고 틀림없이 더 깔끔해 보입니다.
결론
클로저는 JavaScript의 필수 부분이며 더 나은 코드를 작성하려면 클로저를 더 잘 이해해야 합니다. 물론 오래된 폐쇄를 피하십시오.
그리고 항상 그렇듯이 이 기사에 잘못된 정보가 있으면 알려주시면 바로잡겠습니다! 도움이 되었는지 아닌지에 대한 피드백을 듣고 싶습니다!
Reference
이 문제에 관하여(React에서 오래된 클로저 피하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/kaankorkmaz/avoid-stale-closures-in-react-1oai텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)