React 컴포넌트에 강제로 다시 마운트하는 방법은 무엇입니까?


103

조건부 렌더링이있는 뷰 구성 요소가 있다고 가정 해 보겠습니다.

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

MyInput은 다음과 같습니다.

class MyInput extends React.Component {

    ...

    render(){
        return (
            <div>
                <input name={this.props.name} 
                    ref="input" 
                    type="text" 
                    value={this.props.value || null}
                    onBlur={this.handleBlur.bind(this)}
                    onChange={this.handleTyping.bind(this)} />
            </div>
        );
    }
}

employed사실 이라고합시다 . false로 전환하고 다른 뷰가 렌더링 될 때마다 만 unemployment-duration다시 초기화됩니다. 또한 unemployment-reasonfrom 값으로 미리 채워 job-title집니다 (조건이 변경되기 전에 값이 제공된 경우).

두 번째 렌더링 루틴의 마크 업을 다음과 같이 변경하면 :

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

모든 것이 잘 작동하는 것 같습니다. React가 '직위'와 '실업 이유'를 구별하지 못하는 것 같습니다.

내가 뭘 잘못하고 있는지 말해줘 ...


1
무엇 년대 data-reactid의 각의 MyInput(또는 input, DOM에서와 같이) 전후의 요소 employed스위치?
— 크리스

@Chris MyInput 구성 요소가 입력을 <div>. data-reactid속성은 포장 DIV 및 입력 필드 모두 다른 것 같다. job-title입력 ID를 가져옵니다 data-reactid=".0.1.1.0.1.0.1"동안 unemployment-reason입력 ID를 가져옵니다data-reactid=".0.1.1.0.1.2.1"
— O01

1
그리고 unemployment-duration어떨까요?
— 크리스

@Chris 죄송합니다. 너무 빨리 말했습니다. 첫 번째 예 ( "diff me"범위 없음)에서 reactid속성은 job-title및 unemployment-reason에서 동일하지만 두 번째 예 (diff 범위 포함)에서는 서로 다릅니다.
— o01 16.04.04

대한 @ 크리스 속성은 항상 고유합니다. unemployment-durationreactid
— o01

답변:


108

아마도 일어나는 일은 React가 렌더링 사이에 하나의 MyInput( unemployment-duration) 만 추가 되었다고 생각한다는 것 입니다. 따라서 job-title는로 대체되지 않으므로 unemployment-reason미리 정의 된 값이 바뀝니다.

React가 diff를 수행 할 때 key속성 에 따라 어떤 구성 요소가 새로운 구성 요소인지 오래된 구성 요소인지 결정 합니다. 이러한 키가 코드에 제공되지 않으면 자체적으로 생성됩니다.

마지막으로 제공하는 코드 스 니펫이 작동하는 이유는 React가 본질적으로 부모 아래의 모든 요소의 계층 구조를 변경해야하기 때문에 div모든 자식의 다시 렌더링을 트리거 할 것이라고 믿기 때문입니다 (이것이 작동하는 이유입니다). 를 span상단 대신 하단에 추가했다면 이전 요소의 계층 구조가 변경되지 않고 해당 요소가 다시 렌더링되지 않습니다 (문제가 지속됨).

공식 React 문서에 나오는 내용은 다음과 같습니다 .

하위 항목이 (검색 결과에서와 같이) 뒤섞이거나 새 구성 요소가 목록의 맨 앞에 추가되면 (스트림에서와 같이) 상황이 더 복잡해집니다. 렌더 패스에서 각 하위 항목의 ID와 상태를 유지해야하는 경우 키를 할당하여 각 하위 항목을 고유하게 식별 할 수 있습니다.

React가 키가있는 자식을 조정하면 키가있는 자식이 다시 정렬되거나 (재사용 대신) 폐기됩니다.

key부모 div또는 모든 MyInput요소에 고유 한 요소를 직접 제공하여이 문제를 해결할 수 있어야합니다 .

예를 들면 :

render(){
    if (this.state.employed) {
        return (
            <div key="employed">
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div key="notEmployed">
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

또는

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput key="title" ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
                <MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

이제 React가 diff를 수행 할 때가 divs다른 것을 확인하고 모든 자식을 포함하여 다시 렌더링합니다 (첫 번째 예). 2 예에서, DIFF는에 성공합니다 job-title그리고 unemployment-reason그들은 지금 서로 다른 키를 가지고 있기 때문에합니다.

물론 고유 한 키라면 원하는 모든 키를 사용할 수 있습니다.


2017 년 8 월 업데이트

React에서 키가 작동하는 방식에 대한 더 나은 통찰력을 위해 React.js의 고유 키 이해에 대한 제 답변을 읽는 것이 좋습니다 .


2017 년 11 월 업데이트

이 업데이트는 얼마 전에 게시 되었어야했지만 ref이제는 문자열 리터럴을 사용할 수 없습니다 . 예를 들어 ref="job-title"대신 ref={(el) => this.jobTitleRef = el}( 예를 들어) 있어야합니다 . 자세한 내용은 this.refs 를 사용하여 사용 중단 경고에 대한 내 답변을 참조하십시오 .


10
it will determine which components are new and which are old based on their key property.-이었다 ... 키 ... 내 이해
— 래리

1
정말 고마워 ! 또한 맵의 모든 하위 구성 요소가 성공적으로 다시 렌더링되었음을 알아 냈고 그 이유를 이해할 수 없었습니다.
— ValentinVoilean

좋은 힌트는 상태 변수 (예 : id와 같이 변경됨)를 div의 키로 사용하는 것입니다!
— Macilias

200

구성 요소의 키를 변경합니다.

<Component key="1" />
<Component key="2" />

키가 변경되었으므로 구성 요소가 마운트 해제되고 Component의 새 인스턴스가 마운트됩니다.

편집 : 문서화 됨 아마도 파생 상태가 필요하지 않습니다 .

키가 변경되면 React는 현재 구성 요소를 업데이트하는 대신 새 구성 요소 인스턴스를 만듭니다. 키는 일반적으로 동적 목록에 사용되지만 여기에서도 유용합니다.


45
이것은 React 문서에서 훨씬 더 분명해야합니다. 이것은 내가 추구했던 것을 정확히 달성했지만 찾는 데 몇 시간이 걸렸습니다.
— Paul

4
이것은 저에게 큰 도움이되었습니다! 감사! CSS 애니메이션을 재설정해야했지만이를 수행하는 유일한 방법은 강제로 다시 렌더링하는 것입니다. 나는 이것이 반응 문서에서 더 분명해야한다는 데 동의합니다
— Alex. P.

@ Alex.P. 좋은! CSS 애니메이션은 때때로 까다로울 수 있습니다. 예를보고 싶습니다.
— Alex K

1
이 기술을 설명하는 React 문서 : reactjs.org/blog/2018/06/07/…
— GameSalutes

감사합니다. 정말 감사합니다. "randomNumber"와 같은 선언되지 않은 소품에 난수를 공급하려고했지만 작동 한 유일한 소품은 키였습니다.
— ShameWare

5

setState보기에서 사용 하여 employed상태 속성 을 변경 합니다. 이것은 React 렌더 엔진의 예입니다.

 someFunctionWhichChangeParamEmployed(isEmployed) {
      this.setState({
          employed: isEmployed
      });
 }

 getInitialState() {
      return {
          employed: true
      }
 },

 render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

나는 이미 이것을하고있다. 'employed'변수는 뷰 컴포넌트 상태의 일부이며 setState 함수를 통해 변경됩니다. 설명하지 않아서 죄송합니다.
— o01

'employed'변수는 React state의 속성이어야합니다. 코드 예제에서는 명확하지 않습니다.
— 드미트리

this.state.employed를 어떻게 변경합니까? 코드를 보여주세요. 코드의 적절한 위치에서 setState를 사용하고 있습니까?
— Dmitriy

보기 구성 요소는 내 예제가 보여주는 것보다 조금 더 복잡합니다. MyInput 구성 요소 외에도 onChange 핸들러로 'employed'값을 제어하는 ​​라디오 버튼 그룹도 렌더링합니다. onChange 핸들러에서 그에 따라 뷰 컴포넌트의 상태를 설정했습니다. 라디오 버튼 그룹의 값이 변경되면 뷰가 제대로 다시 렌더링되지만 React는 첫 번째 MyInput 구성 요소가 '고용 됨'이 변경되기 전과 동일하다고 생각합니다.
— o01

0

저는 제 앱을 위해 Crud 작업을하고 있습니다. 이것이 내가 한 방법입니다.

import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';

const LifeActionCreate = () => {
  let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();

  const onCreate = e => {
    const db = firebase.firestore();

    db.collection('actions').add({
      label: newLifeActionLabel
    });
    alert('New Life Insurance Added');
    setNewLifeActionLabel('');
  };

  return (
    <Card style={{ padding: '15px' }}>
      <form onSubmit={onCreate}>
        <label>Name</label>
        <input
          value={newLifeActionLabel}
          onChange={e => {
            setNewLifeActionLabel(e.target.value);
          }}
          placeholder={'Name'}
        />

        <Button onClick={onCreate}>Create</Button>
      </form>
    </Card>
  );
};

거기에 몇 가지 React Hooks


SO에 오신 것을 환영합니다! 좋은 답변을 작성하는 방법 을 복습 할 수 있습니다 . 코드를 게시하는 것 외에도 질문을 어떻게 해결했는지에 대한 설명을 추가하십시오.
— displacedtexan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.