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-titleunemployment-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.