Development Tip

setState (…) : 마운트되거나 마운트 된 구성 요소 만 업데이트 할 수 있습니다.

yourdevel 2020. 10. 16. 08:12
반응형

setState (…) : 마운트되거나 마운트 된 구성 요소 만 업데이트 할 수 있습니다. 이것은 일반적으로 마운트되지 않은 구성 요소에서 setState ()를 호출했음을 의미합니다. 이것은 작동하지 않습니다


componentDidMount(prevProps, prevState, prevContext) {
    let [audioNode, songLen] = [this.refs.audio, List.length-1];

    audioNode.addEventListener('ended', () => {
        this._endedPlay(songLen, () => {
            this._currSong(this.state.songIndex);
            this._Play(audioNode);
        });
    });

    audioNode.addEventListener('timeupdate', () => {
        let [remainTime, remainTimeMin, remainTimeSec, remainTimeInfo] = [];

        if(!isNaN(audioNode.duration)) {
            remainTime = audioNode.duration - audioNode.currentTime;
            remainTimeMin = parseInt(remainTime/60);  // 剩余分
            remainTimeSec = parseInt(remainTime%60);  // 剩余秒

            if(remainTimeSec < 10) {
                remainTimeSec = '0'+remainTimeSec;
            }
            remainTimeInfo = remainTimeMin + ':' + remainTimeSec;
            this.setState({'time': remainTimeInfo});
        }
    });
}

componentWillUnmount () {
    let audio = this.refs.audio;
    audio.removeEventListener('timeupdate');
    audio.removeEventListener('ended');
}

오류:

경고 : setState (...) : 마운트되었거나 마운트 된 구성 요소 만 업데이트 할 수 있습니다. 이것은 일반적으로 마운트되지 않은 구성 요소에서 setState ()를 호출했음을 의미합니다. 이건 안돼. 정의되지 않은 구성 요소에 대한 코드를 확인하십시오.

에서 '종료 된'EventListener를 제거 componentWillUnmount했지만 작동하지 않습니다. 나는 추가하기 때문에 this.setState({'time': remainTimeInfo});에서 componentDidMount.


구성 요소에 참조할당 한 다음 상태를 설정하기 전에 참조가 있는지 확인 하여이 문제를 해결했습니다 .

myMethod(){
  if (this.refs.myRef) 
   this.setState({myVar: true});
}

render() {
  return (
    <div ref="myRef">
      {this.state.myVar}
    </div>
  );
}

removeEventListener와 동일한 서명이 있습니다 addEventListener. 리스너를 제거하려면 모든 인수가 정확히 동일해야합니다.

var onEnded = () => {};
audioNode.addEventListener('ended', onEnded, false);

this.cleanup = () => {
  audioNode.removeEventListener('ended', onEnded, false);
}

그리고 componentWillUnmount 호출에서 this.cleanup().


생성자 setState대신 사용했기 때문에이 문제가 발생했습니다 state.

다음 잘못된 코드 변경

constructor(props) {
  super(props);
  this.setState({
    key: ''
  });
}

...에

constructor(props) {
  super(props);
  this.state = {
    key: ''
  }; 
}

Edit : isMounted더 이상 사용되지 않으며 React의 이후 버전에서 제거 될 것입니다. 참조 이를 isMounted는 안티 패턴입니다 .


경고 상태로, 당신은 호출 this.setState하는 A 구성 요소에 있었다 장착하지만 그 이후 마운트 해제되었습니다.

코드가 안전한지 확인하려면 코드를

if (this.isMounted()) {
    this.setState({'time': remainTimeInfo});
}

구성 요소가 여전히 마운트되었는지 확인합니다.


최신 반응 버전을 업데이트 한 이후 동일한 문제에 직면했습니다. 아래와 같이 해결됩니다.

내 코드는

async componentDidMount() {
  const { default: Component } = await importComponent();
  Nprogress.done();
  this.setState({
    component: <Component {...this.props} />
  });
}

로 변경

componentWillUnmount() {
  this.mounted = false;
}
async componentDidMount() {
  this.mounted = true;
  const { default: Component } = await importComponent();
  if (this.mounted) {
    this.setState({
      component: <Component {...this.props} />
    });
  }
}

나는 전에이 문제가 있었고 React 공식 페이지 isMounted is an Antipattern 에 따라 해결했습니다 .

에서 속성 isMounted플래그를 true로 설정하고 에서 componentDidMountfalse로 전환합니다 componentWillUnmount. setState()콜백 할 때 isMounted먼저 확인하십시오 ! 그것은 나를 위해 작동합니다.

state = {
    isMounted: false
  }
  componentDidMount() {
      this.setState({isMounted: true})
  }
  componentWillUnmount(){
      this.setState({isMounted: false})
  }

콜백 :

if (this.state.isMounted) {
 this.setState({'time': remainTimeInfo});}

이 스레드의 많은 답변은 refs를 사용하는 요점을 얻었지만 완전한 예제가 좋을 것이라고 생각합니다. 이벤트 리스너를 사용하고 React 컨텍스트를 벗어나 실제 DOM 노드에서 작동하므로 ref는 표준 솔루션으로 간주되어야합니다. 다음은 완전한 예입니다.

class someComponent extends Component {
  constructor(props) {
    super(props)
    this.node = null
  }
  render() {
    return (
      <div ref={node => { this.node = node }}>Content</div>
    )
  }
  handleEvent(event) {
    if (this.node) {
      this.setState({...})
    }
  }
  componentDidMount() {
    //as soon as render completes, the node will be registered.
    const handleEvent = this.handleEvent.bind(this)
    this.node.addEventListener('click', handleEvent)
  }
  componentWillUnmount() {
    const handleEvent = this.handleEvent.bind(this)
    this.node.removeEventListener('click', handleEvent)
  }
}

addEventListener 및 removeEventListener , 콜백은 익명 내부 클래스가 아니어야하며 동일한 매개 변수를 가져야합니다.


Ajax 요청의 성공 / 실패 콜백에 대한 팝업 (부트 스트랩 모달)을 표시하려고 할 때이 경고가 표시되었습니다. 또한 setState가 작동하지 않고 팝업 모달이 표시되지 않았습니다.

아래는 내 상황-

<Component /> (Containing my Ajax function)
    <ChildComponent />
        <GrandChildComponent /> (Containing my PopupModal, onSuccess callback)

I was calling ajax function of component from grandchild component passing a onSuccess Callback (defined in grandchild component) which was setting state to show popup modal.

I changed it to -

<Component /> (Containing my Ajax function, PopupModal)
    <ChildComponent />
        <GrandChildComponent /> 

Instead I called setState (onSuccess Callback) to show popup modal in component (ajax callback) itself and problem solved.

In 2nd case: component was being rendered twice (I had included bundle.js two times in html).


Having named method in place of the anonymous function in audioNode.addEventListener 's callback should eliminate the subject warning:

    componentDidMount(prevProps, prevState, prevContext) {
    let [audioNode, songLen] = [this.refs.audio, List.length-1];

    audioNode.addEventListener('ended', () => {
        this._endedPlay(songLen, () => {
            this._currSong(this.state.songIndex);
            this._Play(audioNode);
        });
    });

    audioNode.addEventListener('timeupdate', this.callbackMethod );
}

callBackMethod = () => {
    let [remainTime, remainTimeMin, remainTimeSec, remainTimeInfo] = [];

    if(!isNaN(audioNode.duration)) {
        remainTime = audioNode.duration - audioNode.currentTime;
        remainTimeMin = parseInt(remainTime/60);  // 剩余分
        remainTimeSec = parseInt(remainTime%60);  // 剩余秒

        if(remainTimeSec < 10) {
            remainTimeSec = '0'+remainTimeSec;
        }
        remainTimeInfo = remainTimeMin + ':' + remainTimeSec;
        this.setState({'time': remainTimeInfo});
    }
}

And yes, named method is needed anyways because removeEventListener won't work with anonymous callbacks, as mentioned above several times.


  1. Cancel all async operation in componentWillUnmount
  2. Check component is already unmounted when async call setState,
    since isMounted flag is deprecated

참고URL : https://stackoverflow.com/questions/34544314/setstate-can-only-update-a-mounted-or-mounting-component-this-usually-mea

반응형