마운트 해제된 컴포넌트의 Respect - setState()
리액트 컴포넌트에서는 Ajax 요청이 진행 중일 때 단순한 스피너를 구현하려고 합니다.로드 상태를 저장하기 위해 상태를 사용하고 있습니다.
어떤 이유로 인해 내 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;
}
이러한 성공 및 오류 콜백은 마운트 해제 후에도 호출될 수 있으므로 interval 변수를 사용하여 마운트 여부를 확인할 수 있습니다.
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 요소에 대한 참조입니다.
참조 및 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() {
...
}
}
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])
Javascript의 closes 덕분에 가능합니다.
일반적으로 위의 아이디어는 react doc가 권장하는 makeCancelable 접근법에 가까웠습니다.이 접근방식은 명확하게 기술되어 있습니다.
isMounted는 Antiattern입니다.
신용 거래
https://contangaramendy.dev/use-contraction-procription/
후세를 위해
이 경우 이 오류는 Reflux, 콜백, 리다이렉트 및 setState와 관련되어 있습니다.setState를 onDone 콜백으로 전송했지만 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는 "비사용/반패턴"이기 때문에 _mounted 변수를 사용하여 직접 모니터링하는 경우도 있습니다.
참고로.CPromise를 데코레이터와 함께 사용하면 다음과 같은 트릭을 할 수 있습니다(라이브 데모는 이쪽).
export class TestComponent extends React.Component {
state = {};
@canceled(function (err) {
console.warn(`Canceled: ${err}`);
if (err.code !== E_REASON_DISPOSED) {
this.setState({ text: err + "" });
}
})
@listen
@async
*componentDidMount() {
console.log("mounted");
const json = yield this.fetchJSON(
"https://run.mocky.io/v3/7b038025-fc5f-4564-90eb-4373f0721822?mocky-delay=2s"
);
this.setState({ text: JSON.stringify(json) });
}
@timeout(5000)
@async
*fetchJSON(url) {
const response = yield cpFetch(url); // cancellable request
return yield response.json();
}
render() {
return (
<div>
AsyncComponent: <span>{this.state.text || "fetching..."}</span>
</div>
);
}
@cancel(E_REASON_DISPOSED)
componentWillUnmount() {
console.log("unmounted");
}
}
언급URL : https://stackoverflow.com/questions/32903001/react-setstate-on-unmounted-component
'programing' 카테고리의 다른 글
| WooCommerce에서 ID별로 제품 개체 반환 (0) | 2023.04.02 |
|---|---|
| 네트워크 패널이 동작하지 않는다. (0) | 2023.04.02 |
| HTML 만들기: PHP 서버 측과 jQuery 클라이언트 측 (0) | 2023.03.28 |
| 어디서든 Angular UI 모드를 닫는 방법 (0) | 2023.03.28 |
| jq를 사용하여 json의 여러 필드를 순차적으로 구문 분석 및 표시 (0) | 2023.03.28 |