내 반응 구성 요소에서 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 & 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)
);
더
어떤 경우에는 React의 isMounted가 “deprecated / anti-pattern”이기 때문에 _mounted 변수를 사용하여 직접 모니터링했습니다.
답변
반응 후크로 활성화 된 솔루션을 공유합니다 .
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)
}, [])
fetch id 변경에 대한 이전 요청 을 취소 할 때마다 동일한 솔루션을 확장 할 수 있습니다 this.setState
.
React.useEffect(() => {
let isCancelled = false
callApi(id).then(...).catch(...) // similar to above
return () => (isCancelled = true)
}, [id])
이것은 자바 스크립트의 클로저 덕분에 작동합니다 .
일반적으로 위의 아이디어 는 react doc에서 권장 하는 makeCancelable 접근 방식 에 가깝습니다.
isMounted는 Antipattern입니다.