JSX 소품에서 인라인 화살표 함수를 사용하지 말아야하는 이유
JSX에서 화살표 함수 또는 바인딩을 사용하는 것은 함수가 각 렌더링에서 다시 생성되기 때문에 성능을 저하시키는 나쁜 습관입니다.
함수가 생성 될 때마다 이전 함수는 가비지 수집됩니다. 많은 요소를 렌더링하면 애니메이션에서 버벅 거림이 발생할 수 있습니다.
인라인 화살표 함수를 사용하면 PureComponent
s 및 메서드 shallowCompare
에서 사용하는 구성 요소가 shouldComponentUpdate
어쨌든 다시 렌더링됩니다. 화살표 함수 소품은 매번 다시 생성되기 때문에 얕은 비교는 소품의 변경 사항으로 식별하고 구성 요소가 다시 렌더링됩니다.
다음 두 가지 예에서 볼 수 있듯이 인라인 화살표 기능을 사용하면 <Button>
구성 요소가 매번 다시 렌더링됩니다 (콘솔에 '렌더링 버튼'텍스트가 표시됨).
예제 1- 인라인 핸들러가 없는 PureComponent
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
onClick = () => this.setState((prevState) => ({
counter: prevState.counter + 1
}));
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ this.onClick } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
예 2 - PureComponent 와 인라인 핸들러
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ () => this.setState((prevState) => ({
counter: prevState.counter + 1
})) } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
this
인라인 화살표 함수없이 메서드 바인딩
생성자에서 수동으로 메서드 바인딩 :
class Button extends React.Component {
constructor(props, context) {
super(props, context);
this.cb = this.cb.bind(this);
}
cb() {
}
render() {
return (
<button onClick={ this.cb }>Click</button>
);
}
}
제안 클래스 필드 를 화살표 함수와 함께 사용하여 메서드를 바인딩 합니다. 이것은 3 단계 제안이므로 3 단계 사전 설정 또는 클래스 속성 변환 을 바벨 구성 에 추가해야 합니다.
class Button extends React.Component {
cb = () => { // the class property is initialized with an arrow function that binds this to the class
}
render() {
return (
<button onClick={ this.cb }>Click</button>
);
}
}
내부 콜백이있는 함수 구성 요소
함수 구성 요소 내에 내부 함수 (예 : 이벤트 처리기)를 만들면 구성 요소가 렌더링 될 때마다 함수가 다시 만들어집니다. 함수가 소품으로 (또는 컨텍스트를 통해) 자식 구성 요소 ( Button
이 경우)에 전달되면 해당 자식도 다시 렌더링됩니다.
예제 1-내부 콜백이있는 함수 구성 요소 :
const { memo, useState } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
<button onClick={onClick}>Click</button>
));
const Parent = () => {
const [counter, setCounter] = useState(0);
const increment = () => setCounter(counter => counter + 1); // the function is recreated all the time
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
이 문제를 해결하기 위해 콜백을 useCallback()
hook으로 래핑 하고 종속성을 빈 배열로 설정할 수 있습니다.
참고useState
생성 기능의 현재 상태를 제공하는 업데이터 기능을 수용한다. 이런 식으로 현재 상태를의 종속성으로 설정할 필요가 없습니다 useCallback
.
예제 2-useCallback으로 래핑 된 내부 콜백이있는 함수 구성 요소 :
const { memo, useState, useCallback } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
<button onClick={onClick}>Click</button>
));
const Parent = () => {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => setCounter(counter => counter + 1), []);
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>