React Functional Components의 모든 함수 핸들러에서 Callback을 사용해야 합니까?
예를 들어 다음과 같은 컴포넌트가 있다고 합시다.
const Example = () => {
const [counter, setCounter] = useState(0);
const increment = () => setCounter(counter => counter + 1);
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
지나갔을 때onClick
화살표 기능으로 핸들러, myeslint
경고:
error JSX props should not use arrow functions react/jsx-no-bind
이 투고로부터의 회답으로부터 읽었습니다.https://stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind # : ~ : text = Why % 20 your % 20 do not use , previous % 20 function % 20 is % 20 garbage % 20 collected .
단답은 매번 화살표 기능이 재현돼 성능이 떨어지기 때문이다.이 투고에서 제안하는 솔루션 중 하나는 빈 어레이로 useCallback 후크에 랩하는 것입니다.그리고 이걸 바꾸면 eslint 경고는 정말 사라집니다.
const Example = () => {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => setCounter(counter => counter + 1), []);
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
그러나 useCallback을 과도하게 사용하면 useCallback의 오버헤드로 인해 결과적으로 퍼포먼스가 저하된다는 의견도 있습니다.예를 들면, https://kentcdodds.com/blog/usememo-and-usecallback 입니다.
이게 날 혼란스럽게 한다고?기능 컴포넌트의 경우 인라인 함수 핸들러를 다룰 때 화살표 함수를 쓸까요(eslint를 무시함) 아니면 항상 useCallback으로 래핑해야 합니까?
단답은 매번 화살표 기능이 재현돼 성능이 떨어지기 때문이다.
이것은 일반적인 오해입니다.화살표 기능은 어느 쪽이든 매번 재생성됩니다(단,useCallback
후속 제품은 즉시 폐기할 수 있습니다.)뭐?useCallback
는 콜백을 사용하는 자 컴포넌트가 메모되어 있는 경우 다시 콜백되지 않도록 합니다.
그럼 오해부터 살펴볼까요?고려 사항:useCallback
호출:
const increment = useCallback(() => setCounter(counter => counter + 1), []);
다음과 같이 실행됩니다.
첫 번째 인수를 평가합니다.
() => setCounter(counter => counter + 1)
, 함수를 만듭니다.두 번째 인수를 평가합니다.
[]
, 어레이 작성불러
useCallback
이 두 개의 인수로 함수를 되돌립니다.
사용하지 않을 경우 가지고 있는 것과 비교해 보십시오.useCallback
:
const increment = () => setCounter(counter => counter + 1);
훨씬 간단합니다. 함수를 만듭니다.그러면 위의 2번과 3번을 할 필요가 없습니다.
그럼 뭐로 넘어갑시다useCallback
그게 실제로 도움이 되거든요.콜백의 사용처를 살펴보겠습니다.
<Button onClick={increment} />
자, 예를 들어Button
또는 이와 유사합니다.한다면increment
컴포넌트가 렌더링될 때마다 변경됩니다.Button
는 컴포넌트가 변경될 때마다 다시 작성해야 합니다.렌더 간에 재사용할 수 없습니다., 만약 ★★★★★★★★★★★★★★★★.increment
에) 입니다.useCallback
을 사용)를 호출했을 된 결과입니다.Button
다시 호출할 필요가 없기 때문에 다시 사용할 수 있습니다.
다음은 예를 제시하겠습니다.
const { useState, useCallback } = React;
const Button = React.memo(function Button({onClick, children}) {
console.log("Button called");
return <button onClick={onClick}>{children}</button>;
});
function ComponentA() {
console.log("ComponentA called");
const [count, setCount] = useState(0);
// Note: Safe to use the closed-over `count` here if `count `updates are
// triggered by clicks or similar events that definitely render, since
// the `count` that `increment` closes over won't be stale.
const increment = () => setCount(count + 1);
return (
<div>
{count}
<Button onClick={increment}>+</Button>
</div>
);
}
function ComponentB() {
console.log("ComponentB called");
const [count, setCount] = useState(0);
// Note: Can't use `count` in `increment`, need the callback form because
// the `count` the first `increment` closes over *will* be slate after
// the next render
const increment = useCallback(
() => setCount(count => count + 1),
[]
);
return (
<div>
{count}
<Button onClick={increment}>+</Button>
</div>
);
}
ReactDOM.render(
<div>
A:
<ComponentA />
B:
<ComponentB />
</div>,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
해 주세요.ComponentA
전화하다Button
한 번 ''를 클릭해 주세요.ComponentB
그렇지 않다.
신은언 언것 ?것? ??? ???주로 컴포넌트의 가 자주 은 아마 것입니다. 내용은 을 받지 increment
을 주지 Button
그리고 만약Button
렌더링할 때 중요한 작업을 수행해야 합니다. Button
그렇지 않을 수도 있지만 다른 아이 구성 요소도 그럴 수 있습니다.
를 들면, 「」는,useCallback
에서는, 「아까운 사람」이라고 하는 것은 할 것입니다.count
은 「일부러」를 의미하기 에, 「일부러」를 합니다.Button
다음의 를 불문하고 재접속할 가 있습니다.
const { useState, useCallback } = React;
const Button = React.memo(function Button({onClick, children}) {
console.log("Button called");
return <button onClick={onClick}>{children}</button>;
});
function ComponentA() {
console.log("ComponentA called");
const [count, setCount] = useState(0);
// Note: Safe to use the closed-over `count` here if `count `updates are
// triggered by clicks or similar events that definitely render, since
// the `count` that `increment` closes over won't be stale.
const increment = () => setCount(count + 1);
return (
<div>
<Button onClick={increment}>{count}</Button>
</div>
);
}
function ComponentB() {
console.log("ComponentB called");
const [count, setCount] = useState(0);
// Note: Can't use `count` in `increment`, need the callback form because
// the `count` the first `increment` closes over *will* be slate after
// the next render
const increment = useCallback(
() => setCount(count => count + 1),
[]
);
return (
<div>
<Button onClick={increment}>{count}</Button>
</div>
);
}
ReactDOM.render(
<div>
A:
<ComponentA />
B:
<ComponentB />
</div>,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
, 「 」, 「 」라고 하는 도 주의해 주세요.useCallback
무료가 아니라 콜백의 코드에 영향을 줍니다.에 있는 .ComponentA
★★★★★★★★★★★★★★★★★」ComponentB
를 참조해 주세요. ComponentA
하지 않음)useCallback
의할 수 .count
.() => setCount(count + 1)
그 에 있는 건ComponentB
인 '콜백'을 .() => setCount(count => count + 1)
첫 increment
「」가 됩니다.count
종료는 오래된 것입니다.카운트는 1이 됩니다만, 그 이상은 아닙니다.
를 여러가지 을 만들고 경우useCallback
★★★★★★★★★★★★★★★★★」useMemo
메모리 이탈이 너무 심할 수 있습니다(매우 드문 경우).ref를 사용하면 이를 방지할 수 있습니다.업데이트에 대해 알아보겠습니다.ComponentB
대신 ref를 사용한다.useCallback
:
const incrementRef = useRef(null);
if (!incrementRef.current /* || yourDependenciesForItChange*/) {
// Note: Can't use `count` in `increment`, need the callback form because
// the `count` the first `increment` closes over *will* be slate after
// the next render
incrementRef.current = () => setCount(count => count + 1);
}
const increment = incrementRef.current;
" " "만됩니다.increment
(예에서는에) 번 (사용할 수 있는 기능이 없습니다)를 사용하는 일은 없습니다.useCallback
이 'ref'이기 가 있습니다.null
후 가 처음 되었을 때, 함수가 「」라고 null
함수를 생성하여 참조에 추가합니다. ★★★★★★★★★★★★★★★★★.increment
한 번만 생성됩니다.
에서는 우리가 .setCount
increment
피할수 , 피할 수 피할 수 있다.
const incrementRef = useRef(null);
if (!incrementRef.current) {
// Note: Can't use `count` in `increment`, need the callback form because
// the `count` the first `increment` closes over *will* be slate after
// the next render
const incrementCallback = count => count + 1;
incrementRef.current = () => setCount(incrementCallback);
}
const increment = incrementRef.current;
const { useState, useRef } = React;
const Button = React.memo(function Button({onClick, children}) {
console.log("Button called");
return <button onClick={onClick}>{children}</button>;
});
function ComponentA() {
console.log("ComponentA called");
const [count, setCount] = useState(0);
// Note: Safe to use the closed-over `count` here if `count `updates are
// triggered by clicks or similar events that definitely render, since
// the `count` that `increment` closes over won't be stale.
const increment = () => setCount(count + 1);
return (
<div>
{count}
<Button onClick={increment}>+</Button>
</div>
);
}
function ComponentB() {
console.log("ComponentB called");
const [count, setCount] = useState(0);
const incrementRef = useRef(null);
if (!incrementRef.current) {
// Note: Can't use `count` in `increment`, need the callback form because
// the `count` the first `increment` closes over *will* be slate after
// the next render
const incrementCallback = count => count + 1;
incrementRef.current = () => setCount(incrementCallback);
}
const increment = incrementRef.current;
return (
<div>
{count}
<Button onClick={increment}>+</Button>
</div>
);
}
ReactDOM.render(
<div>
A:
<ComponentA />
B:
<ComponentB />
</div>,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
불필요한 함수 생성을 회피한다는 점에서 이는 11이 됩니다. :-)
이 컴포넌트는 제1레벨의 최적화를 필요로 하는 드문 컴포넌트입니다.제2레벨의 최적화를 필요로 하는 경우는 거의 없습니다.하지만 최적화가 필요한 경우에는 그렇게 해야 합니다.
언급URL : https://stackoverflow.com/questions/64134566/should-we-use-usecallback-in-every-function-handler-in-react-functional-componen
'sourcetip' 카테고리의 다른 글
각도 1.x에서 종속성을 느리게 로드하려면 Browserify 또는 Webpack을 사용해야 합니까? (0) | 2023.03.09 |
---|---|
오라클 데이터베이스에서 무작위로 레코드를 가져오려면 어떻게 해야 합니까? (0) | 2023.03.09 |
전환이 포함된 리액트모달(에 추가)을 작성하려면 어떻게 해야 합니까? (0) | 2023.03.09 |
WordPress 다중 사이트 설정에서 다른 사이트의 게시물을 표시하려면 어떻게 해야 합니까? (0) | 2023.03.09 |
HTML 양식을 제출하지 않도록 합니다. (0) | 2023.03.09 |