JSX 소품이 화살표 함수 나 바인드를 사용하지 않는 이유는 무엇입니까?


103

React 앱에서 Lint를 실행하고 있는데이 오류가 발생합니다.

error    JSX props should not use arrow functions        react/jsx-no-bind

그리고 이것은 내가 화살표 기능을 실행하는 곳입니다 (내부 onClick).

{this.state.photos.map(tile => (
  <span key={tile.img}>
    <Checkbox
      defaultChecked={tile.checked}
      onCheck={() => this.selectPicture(tile)}
      style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
    />
    <GridTile
      title={tile.title}
      subtitle={<span>by <b>{tile.author}</b></span>}
      actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
    >
      <img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
    </GridTile>
  </span>
))}

피해야 할 나쁜 습관입니까? 그리고 그것을 수행하는 가장 좋은 방법은 무엇입니까?

답변:


170

JSX 소품에서 인라인 화살표 함수를 사용하지 말아야하는 이유

JSX에서 화살표 함수 또는 바인딩을 사용하는 것은 함수가 각 렌더링에서 다시 생성되기 때문에 성능을 저하시키는 나쁜 습관입니다.

  1. 함수가 생성 될 때마다 이전 함수는 가비지 수집됩니다. 많은 요소를 렌더링하면 애니메이션에서 버벅 거림이 발생할 수 있습니다.

  2. 인라인 화살표 함수를 사용하면 PureComponents 및 메서드 shallowCompare에서 사용하는 구성 요소가 shouldComponentUpdate어쨌든 다시 렌더링됩니다. 화살표 함수 소품은 매번 다시 생성되기 때문에 얕은 비교는 소품의 변경 사항으로 식별하고 구성 요소가 다시 렌더링됩니다.

다음 두 가지 예에서 볼 수 있듯이 인라인 화살표 기능을 사용하면 <Button>구성 요소가 매번 다시 렌더링됩니다 (콘솔에 '렌더링 버튼'텍스트가 표시됨).

예제 1- 인라인 핸들러가 없는 PureComponent

예 2 - PureComponent 인라인 핸들러

this인라인 화살표 함수없이 메서드 바인딩

  1. 생성자에서 수동으로 메서드 바인딩 :

    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>
        );
      }
    }
  2. 제안 클래스 필드 를 화살표 함수와 함께 사용하여 메서드를 바인딩 합니다. 이것은 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-내부 콜백이있는 함수 구성 요소 :

이 문제를 해결하기 위해 콜백을 useCallback()hook으로 래핑 하고 종속성을 빈 배열로 설정할 수 있습니다.

참고useState 생성 기능의 현재 상태를 제공하는 업데이터 기능을 수용한다. 이런 식으로 현재 상태를의 종속성으로 설정할 필요가 없습니다 useCallback.

예제 2-useCallback으로 래핑 된 내부 콜백이있는 함수 구성 요소 :


3
상태 비 저장 구성 요소에서이를 어떻게 달성합니까?
lux

4
상태 비 저장 (함수) 구성 요소에는가 this없으므로 바인딩 할 항목이 없습니다. 일반적으로 메서드는 래퍼 스마트 구성 요소에 의해 제공됩니다.
Ori Drori

39
@OriDrori : 콜백에서 데이터를 전달해야 할 때 어떻게 작동합니까? onClick={() => { onTodoClick(todo.id) }
adam-beck

4
@ adam-beck-클래스의 콜백 메서드 정의 안에 추가합니다 cb() { onTodoClick(this.props.todo.id); }.
Ori Drori

2
@ adam-beck 나는 이것이 useCallback동적 가치 로 사용하는 방법이라고 생각 합니다. stackoverflow.com/questions/55006061/…
Shota Tamura

9

이는 화살표 함수가 JSX 속성에서 사용되는 경우 각 렌더링에서 함수의 새 인스턴스를 분명히 생성하기 때문입니다. 이것은 가비지 컬렉터에 큰 부담을 줄 수 있으며 또한 함수가 재사용되는 대신 버려 질 것이기 때문에 브라우저가 "핫 경로"를 최적화하는 것을 방해합니다.

https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md 에서 전체 설명과 추가 정보를 볼 수 있습니다.


뿐만 아니라. 매번 새 함수 인스턴스를 생성하면 상태가 수정되고 구성 요소의 상태가 수정되면 다시 렌더링됩니다. React를 사용하는 주된 이유 중 하나는 변경되는 요소 만 렌더링하는 것이므로 bind여기에서 또는 화살표 기능을 사용 하는 것은 발을 쏘는 것입니다. 그러나 특히 목록 등에서 핑 배열 로 작업하는 경우에는 잘 문서화 되어 있지 않습니다map .
hippietrail

"매번 새로운 함수 인스턴스를 생성하는 것은 상태가 수정됨을 의미합니다."그 의미는 무엇입니까? 질문에 전혀에는 상태가 없습니다
apieceofbart


4

이와 같은 인라인 함수를 사용하는 것은 완벽합니다. Linting 규칙이 오래되었습니다.

이 규칙은 화살표 기능이 흔하지 않았고 사람들이 .bind (this)를 사용했던 때부터 시작되었습니다. Chrome 49에서 성능 문제가 수정되었습니다.

인라인 함수를 자식 구성 요소에 소품으로 전달하지 않도록주의하십시오.

React Router의 저자 인 Ryan Florence는 이에 대해 훌륭한 글을 썼습니다.

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578


인라인 화살표 기능을 사용하여 구성 요소에 대한 단위 테스트를 작성하는 방법을 보여 주시겠습니까?
krankuba

1
@krankuba 이것은이 질문에 관한 것이 아닙니다. 인라인으로 정의되지 않았지만 여전히 테스트 할 수없는 익명 함수를 전달할 수 있습니다.
sbaechler

-1

react-cached-handler 라이브러리를 사용하여 화살표 함수를 사용할 수 있으며 다시 렌더링 성능에 대해 걱정할 필요가 없습니다.

참고 : 내부적으로는 지정된 키로 화살표 기능을 캐시하므로 다시 렌더링 할 필요가 없습니다!

render() {

  return <div>
  {
        this.props.photos.map(photo=>
          <Photo key={photo.url}
            onClick={this.handler(photo.url, (url) => { 
                 console.log(url) })}
          />)
   }
 </div>

}

다른 기능들:

  • 명명 된 핸들러
  • 화살표 기능으로 이벤트 처리
  • 키, 사용자 지정 인수 및 원래 이벤트에 대한 액세스
  • 컴포넌트 렌더링 성능
  • 핸들러를위한 커스텀 컨텍스트

문제는 왜 우리가 그것을 사용할 수 없다는 것이 었습니다. 다른 해킹과 함께 사용하는 방법이 아닙니다.
kapil

-1

JSX 소품이 화살표 함수 나 바인드를 사용하지 않는 이유는 무엇입니까?

대부분 인라인 함수는 최적화 된 구성 요소의 메모 화를 중단 할 수 있기 때문입니다.

전통적으로 React의 인라인 함수에 대한 성능 문제는 각 렌더링에서 새 콜백을 전달하면 shouldComponentUpdate자식 구성 요소의 최적화 가 어떻게 중단되는지와 관련이 있습니다. ( 문서 )

추가 기능 생성 비용이 적습니다.

Function.prototype.bind 여기서 해결 성능 문제와 화살표 함수는 기본 기능이거나 바벨에 의해 일반 함수로 변환됩니다. 두 경우 모두 느리지 않다고 가정 할 수 있습니다. ( 반응 훈련 )

나는 함수 생성이 비싸다고 주장하는 사람들이 항상 잘못된 정보를 받았다고 생각합니다 (React 팀은 이것을 결코 말하지 않았습니다). ( 트윗 )

react/jsx-no-bind규칙 은 언제 유용합니까?

메모 된 구성 요소가 의도 한대로 작동하는지 확인하려고합니다.

  • React.memo (기능 구성 요소)
  • PureComponent또는 사용자 정의 shouldComponentUpdate(클래스 구성 요소 용)

이 규칙에 따라 안정적인 함수 개체 참조가 전달됩니다. 따라서 위의 구성 요소는 이전 소품이 변경되지 않은 경우 다시 렌더링을 방지하여 성능을 최적화 할 수 있습니다.

ESLint 오류를 해결하는 방법은 무엇입니까?

클래스 : 핸들러를 메서드로 정의하거나 바인딩을 위한 클래스 속성 을 정의합니다 this.
후크 : useCallback.

중앙 필드

대부분의 경우 인라인 함수는 사용하기 매우 편리하고 성능 요구 사항 측면에서 절대적으로 좋습니다. 안타깝게도이 규칙은 메모 된 구성 요소 유형으로 만 제한 될 수 없습니다. 그래도 전체적으로 사용하려면 간단한 DOM 노드에 대해 비활성화 할 수 있습니다 .

rules: {
  "react/jsx-no-bind": [ "error", { ignoreDOMComponents: true } ],
}

const Comp = () => <span onClick={() => console.log("Hello!")} />; // no warning
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.