React 키의 작동 방식과이를 사용하여 할 수있는 재미있는 작업

React는 key조정 단계 에서 속성을 사용하여 다음 렌더링에 재사용 할 수있는 요소를 결정합니다. 동적 목록에 중요합니다. React는 새 요소의 키를 이전 키와 비교하고 1) 새 키가있는 구성 요소를 마운트합니다. 2) 키가 더 이상 사용되지 않는 구성 요소를 마운트 해제합니다.

많은 React 개발자가 index키로 사용해서는 안된다는 일반적인 조언을 들었습니다 . 그러나 keys를 나쁜 방식으로 사용할 때 정확히 무엇이 잘못 될 수 있습니까? 키를 가지고 놀 때 또 무엇을 할 수 있습니까?

더 나은 이해를 위해 inputs 목록을 렌더링하는 예를 살펴 보겠습니다 . 버튼을 클릭하면 목록 Front앞에 텍스트와 함께 새 항목이 삽입 됩니다.

import React from "react";import { render } from "react-dom";class Item extends React.PureComponent { state = { text: this.props.text }; onChange = event => { this.setState({ text: event.target.value }); }; componentDidMount() { console.log("Mounted ", this.props.text); } componentWillUnmount() { console.log("Unmounting ", this.props.text); } render() { console.log("rerendering ", this.props.text); const { text } = this.state; return ( 
  • ); }}class App extends React.Component { state = { items: [ { text: "First", id: 1 }, { text: "Second", id: 2 } ] }; addItem = () => { const items = [{ text: "Front", id: Date.now() }, ...this.state.items]; this.setState({ items }); }; render() { return (
      {this.state.items.map((item, index) => ( ))}
    Add Item ); }}render(, document.getElementById("root"));

    index키로 사용 하면 다음이 발생합니다.

    CodeSandbox

    CodeSandbox는 웹 애플리케이션 용으로 맞춤화 된 온라인 편집기입니다. codesandbox.io

    대신 Item텍스트 가있는 다른 항목 이 목록 뒤에 삽입되면 어떻게됩니까? 다음과 같은 일이 발생합니다.SecondFront

    1. Item is an uncontrolled component: 사용자가 input필드에 쓰는 텍스트는 다음 과 같이 저장됩니다.state
    2. 새 데이터 항목 { text: "Front" }이 목록 데이터의 시작 부분에 삽입됩니다.
    3. 목록은 인덱스 값으로 다시 렌더링 됩니다 key. 이전 구성 요소는 처음 두 위해 다시 사용된다 그래서 데이터 항목 및 올바른 소품을 부여 Front하고 First있지만, 상태는 업데이트되지 않습니다 Item. 이것이 처음 두 구성 요소 인스턴스가 동일한 텍스트를 유지하는 이유입니다.
    4. key: 2일치하는 이전 키가 없기 때문에에 대한 새 구성 요소 인스턴스가 생성 됩니다. 그것은 가득 props마지막의 목록 데이터 항목 입니다 Second.

    또 다른 흥미로운 점은 render발생 하는 전화입니다. 항목은 PureComponent이므로 text소품 (또는 상태)이 변경 될 때만 업데이트됩니다 .

    rerendering Frontrerendering Firstrerendering SecondMounted Second

    모든 구성 요소가 다시 렌더링됩니다. 이 갖는 요소로 인해 발생하는 key: 0첫 번째 데이터 아이템에 대한 재사용 및 수신 props하지만, 제 1 데이터 항목은 현재 새로운 Front트리거링 개체 render. 이전 데이터 항목이 이제 모두 한 곳씩 이동되기 때문에 다른 구성 요소에서도 마찬가지입니다.

    그래서 수정은 무엇입니까? 수정은 간단합니다. 각 목록 데이터 항목 을 생성id 마다 한 번만 고유하게 부여합니다 (렌더 할 마다 아님!). 모든 구성 요소 인스턴스는 해당 데이터 항목과 일치합니다. 그들은 props이전과 똑같은 것을 받고 이것은 다른 render.

    id지금은 동적 목록에서 s 를 사용하여 발생하는 성능 이점을 무시하겠습니다 . 이 예제는 키로 인해 발생 하는 버그는 내부 상태 를 유지 하는 제어되지 않는 구성 요소 와 관련해서 만 발생 한다는 것을 보여줍니다 .

    Item제어 된 구성 요소로 다시 작성 하면 상태를 제거하여 버그가 사라집니다.

    왜? 다시 말하지만, 버그가 다른 데이터 항목에 대해 구성 요소를 재사용 했기 때문 입니다. 따라서 내부 상태는 여전히 이전 데이터 항목의 상태를 반영 하지만 다른 항목소품입니다 . 상태를 완전히 제거하여 구성 요소를 제어하면 더 이상 이러한 불일치가 발생하지 않습니다. (그러나 불필요한 다시 렌더링에는 여전히 문제가 있습니다.)

    키를 남용하여 손상된 타사 구성 요소 수정

    React는 key여러 요소를 일치 시킬 때 s 만 필요 하므로 단일 자식에 키를 설정할 필요가 없습니다. 그러나 단일 하위 구성 요소에 키를 설정하는 것이 여전히 유용 할 수 있습니다.

    키를 변경하면 React는 전체 구성 요소를 버리고 (마운트 해제) 그 자리에 새 구성 요소 인스턴스를 마운트합니다. 이것이 왜 유용할까요?

    다시 한 번, 제어되지 않는 구성 요소 로 돌아갑니다 . 경우에 따라 타사 구성 요소를 사용하고 있으며 해당 코드를 수정하여 제어 할 수 없습니다. 구성 요소가 몇 가지 내부 상태를 가지고 있으며,이 나쁜 방식으로 구현 것 (예를 들어, 상태 만 도출되면 일단 생성자 있지만, getDerivedStateFromProps/ componentWillReceiveProps에 구현되지 재발생 반영 props내부 상태의 변화를) 표준은 도구 상자가 당신을 도울 수 반작용 여기. 없습니다 forceRemount.

    그러나이 key구성 요소에 새 구성 요소를 설정하여 새 구성 요소를 완전히 초기화하는 원하는 동작을 얻을 수 있습니다. 오래된 구성 요소가 마운트 해제되고, 새가 새가 장착됩니다 props를 초기화 state.

    TL; DR :

    index키로 사용하면 다음 을 수행 할 수 있습니다.

    1. 불필요한 다시 렌더링으로 이어집니다
    2. 목록 항목이 제어되지 않는 구성 요소 이지만 여전히 사용하는 경우 버그를 소개 합니다.props

    key속성은 구성 요소를 완전히 다시 마운트하는 데 사용할 수 있으며, 때때로 유용 할 수 있습니다.

    원래 cmichel.io에 게시 됨