Programing

React-마운트 해제 된 구성 요소의 setState ()

crosscheck 2020. 10. 6. 07:52
반응형

React-마운트 해제 된 구성 요소의 setState ()


내 반응 구성 요소에서 ajax 요청이 진행되는 동안 간단한 회 전자를 구현하려고합니다-im은 상태를 사용하여 로딩 상태를 저장합니다.

어떤 이유로 내 React 구성 요소의 아래 코드 조각 이이 오류를 발생시킵니다.

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

첫 번째 setState 호출을 제거하면 오류가 사라집니다.

constructor(props) {
  super(props);
  this.loadSearches = this.loadSearches.bind(this);

  this.state = {
    loading: false
  }
}

loadSearches() {

  this.setState({
    loading: true,
    searches: []
  });

  console.log('Loading Searches..');

  $.ajax({
    url: this.props.source + '?projectId=' + this.props.projectId,
    dataType: 'json',
    crossDomain: true,
    success: function(data) {
      this.setState({
        loading: false
      });
    }.bind(this),
    error: function(xhr, status, err) {
      console.error(this.props.url, status, err.toString());
      this.setState({
        loading: false
      });
    }.bind(this)
  });
}

componentDidMount() {
  setInterval(this.loadSearches, this.props.pollInterval);
}

render() {

    let searches = this.state.searches || [];


    return (<div>
          <Table striped bordered condensed hover>
          <thead>
            <tr>
              <th>Name</th>
              <th>Submit Date</th>
              <th>Dataset &amp; Datatype</th>
              <th>Results</th>
              <th>Last Downloaded</th>
            </tr>
          </thead>
          {
          searches.map(function(search) {

                let createdDate = moment(search.createdDate, 'X').format("YYYY-MM-DD");
                let downloadedDate = moment(search.downloadedDate, 'X').format("YYYY-MM-DD");
                let records = 0;
                let status = search.status ? search.status.toLowerCase() : ''

                return (
                <tbody key={search.id}>
                  <tr>
                    <td>{search.name}</td>
                    <td>{createdDate}</td>
                    <td>{search.dataset}</td>
                    <td>{records}</td>
                    <td>{downloadedDate}</td>
                  </tr>
                </tbody>
              );
          }
          </Table >
          </div>
      );
  }

질문은 구성 요소가 이미 마운트되어 있어야 할 때이 오류가 발생하는 이유입니다 (componentDidMount에서 호출 됨). 구성 요소가 마운트되면 상태를 설정하는 것이 안전하다고 생각합니까?


렌더링 기능을 보지 않고는 조금 힘들다. 해야 할 일을 이미 발견 할 수 있지만 인터벌을 사용할 때마다 언 마운트시이를 지워야합니다. 그래서:

componentDidMount() {
    this.loadInterval = setInterval(this.loadSearches, this.props.pollInterval);
}

componentWillUnmount () {
    this.loadInterval && clearInterval(this.loadInterval);
    this.loadInterval = false;
}

이러한 성공 및 오류 콜백은 마운트 해제 후에도 계속 호출 될 수 있으므로 간격 변수를 사용하여 마운트되었는지 확인할 수 있습니다.

this.loadInterval && this.setState({
    loading: false
});

이것이 도움이되기를 바랍니다. 이것이 작업을 수행하지 않으면 렌더링 기능을 제공하십시오.

건배


질문은 구성 요소가 이미 마운트되어 있어야 할 때이 오류가 발생하는 이유입니다 (componentDidMount에서 호출 됨). 구성 요소가 마운트되면 상태를 설정하는 것이 안전하다고 생각합니까?

그것은되어 있지 에서 호출 componentDidMount. 귀하의 componentDidMount급부상하지 않는 스택, 타이머 핸들러의 스택에서 실행됩니다 콜백 함수 componentDidMount. 분명히 콜백 ( this.loadSearches)이 실행될 때 구성 요소가 마운트 해제되었습니다.

그래서 받아 들여진 대답은 당신을 보호 할 것입니다. 비동기 함수 (일부 핸들러에 이미 제출 됨)를 취소 할 수없는 다른 비동기 API를 사용하는 경우 다음을 수행 할 수 있습니다.

if (this.isMounted())
     this.setState(...

이는 특히 API가 취소 기능을 제공하는 경우 (에서 setInterval와 같이 clearInterval) 러그 아래에서 물건을 훑어 보는 것처럼 느껴지지만 모든 경우에보고하는 오류 메시지를 제거합니다 .


다른 옵션이 필요한 사람에게는 ref 속성의 콜백 메서드가 해결 방법이 될 수 있습니다. handleRef의 매개 변수는 div DOM 요소에 대한 참조입니다.

refs 및 DOM에 대한 자세한 정보 : https://facebook.github.io/react/docs/refs-and-the-dom.html

handleRef = (divElement) => {
 if(divElement){
  //set state here
 }
}

render(){
 return (
  <div ref={this.handleRef}>
  </div>
 )
}

class myClass extends Component {
  _isMounted = false;

  constructor(props) {
    super(props);

    this.state = {
      data: [],
    };
  }

  componentDidMount() {
    this._isMounted = true;
    this._getData();
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  _getData() {
    axios.get('https://example.com')
      .then(data => {
        if (this._isMounted) {
          this.setState({ data })
        }
      });
  }


  render() {
    ...
  }
}

후손에게는

우리의 경우이 오류는 Reflux, 콜백, 리디렉션 및 setState와 관련이 있습니다. onDone 콜백에 setState를 보냈지 만 onSuccess 콜백에 대한 리디렉션도 보냈습니다. 성공의 경우 onSuccess 콜백이 onDone 전에 실행 됩니다. 이로 인해 시도 된 setState 전에 리디렉션발생합니다 . 따라서 마운트되지 않은 구성 요소에 대한 오류 setState.

환류 저장 조치 :

generateWorkflow: function(
    workflowTemplate,
    trackingNumber,
    done,
    onSuccess,
    onFail)
{...

수정 전 전화 :

Actions.generateWorkflow(
    values.workflowTemplate,
    values.number,
    this.setLoading.bind(this, false),
    this.successRedirect
);

수정 후 전화 :

Actions.generateWorkflow(
    values.workflowTemplate,
    values.number,
    null,
    this.successRedirect,
    this.setLoading.bind(this, false)
);

In some cases, since React's isMounted is "deprecated/anti-pattern", we've adopted the use of a _mounted variable and monitoring it ourselves.


Share a solution enabled by react hooks.

React.useEffect(() => {
  let isSubscribed = true

  callApi(...)
    .catch(err => isSubscribed ? this.setState(...) : Promise.reject({ isSubscribed, ...err }))
    .then(res => isSubscribed ? this.setState(...) : Promise.reject({ isSubscribed }))
    .catch(({ isSubscribed, ...err }) => console.error('request cancelled:', !isSubscribed))

  return () => (isSubscribed = false)
}, [])

the same solution can be extended to whenever you want to cancel previous requests on fetch id changes, otherwise there would be race conditions among multiple in-flight requests (this.setState called out of order).

React.useEffect(() => {
  let isCancelled = false

  callApi(id).then(...).catch(...) // similar to above

  return () => (isCancelled = true)
}, [id])

this works thanks to closures in javascript.

In general, the idea above was close to the makeCancelable approach recommended by the react doc, which clearly states

isMounted is an Antipattern

Credit

https://juliangaramendy.dev/use-promise-subscription/

참고URL : https://stackoverflow.com/questions/32903001/react-setstate-on-unmounted-component

반응형