componentDidMount()
React Native에서 비동기 함수로 사용 하는 것이 좋습니까? 아니면 피해야합니까?
AsyncStorage
구성 요소가 마운트 될 때 정보를 얻을 필요가 있지만 가능하게하는 유일한 방법은 componentDidMount()
함수를 비동기 로 만드는 것 입니다.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
그것에 문제가 있습니까?이 문제에 대한 다른 해결책이 있습니까?
답변
차이점을 지적하고 문제를 일으킬 수있는 방법을 결정하는 것으로 시작하겠습니다.
다음은 async 및 “sync” componentDidMount()
수명주기 방법 의 코드입니다 .
// This is typescript code
componentDidMount(): void { /* do something */ }
async componentDidMount(): Promise<void> {
/* do something */
/* You can use "await" here */
}
코드를 보면 다음과 같은 차이점을 알 수 있습니다.
async
키워드 : 타이프 라이터, 이것은 단지 코드 마커입니다. 그것은 두 가지 일을합니다 :- 반환 유형을
Promise<void>
대신 강제로 설정하십시오void
. 반환 유형을 약속이 아닌 것으로 명시 적으로 지정하면 (예 : void) typescript에서 오류가 발생합니다. await
메소드 내에서 키워드 를 사용할 수 있습니다.
- 반환 유형을
- 반환 형식이 변경됩니다
void
에Promise<void>
- 이제이 작업을 수행 할 수 있습니다.
async someMethod(): Promise<void> { await componentDidMount(); }
- 이제이 작업을 수행 할 수 있습니다.
-
await
메소드 내에서 키워드를 사용 하고 일시적으로 실행을 일시 중지 할 수 있습니다 . 이처럼 :async componentDidMount(): Promise<void> { const users = await axios.get<string>("http://localhost:9001/users"); const questions = await axios.get<string>("http://localhost:9001/questions"); // Sleep for 10 seconds await new Promise(resolve => { setTimeout(resolve, 10000); }); // This line of code will be executed after 10+ seconds this.setState({users, questions}); return Promise.resolve(); }
이제 어떻게 문제를 일으킬 수 있습니까?
async
키워드는 절대적으로 무해하다.-
componentDidMount()
반환 유형Promise<void>
도 무해 하므로 메소드를 호출 해야하는 상황을 상상할 수 없습니다 .키워드가
Promise<void>
없는 반환 유형을 가진 메소드를 호출하면 반환 유형이 인 메소드를 호출하는await
것과 차이가 없습니다void
. -
componentDidMount()
실행 지연 후 수명주기 방법이 없기 때문에 꽤 안전 해 보입니다. 그러나 문제가 있습니다.위의 내용
this.setState({users, questions});
은 10 초 후에 실행됩니다. 지연 시간의 중간에 또 다른 …this.setState({users: newerUsers, questions: newerQuestions});
… 성공적으로 실행되었으며 DOM이 업데이트되었습니다. 결과는 사용자에게 공개되었습니다. 시계는 계속 똑딱 거리고 10 초가 경과했습니다.
this.setState(...)
그런 다음 지연 이 실행되고 DOM은 다시 이전 사용자와 이전 질문으로 업데이트됩니다. 결과는 사용자에게도 표시됩니다.
=> 방법 async
과 함께 사용 하는 것이 안전합니다 (약 100 % 확실하지 않습니다) componentDidMount()
. 나는 그것의 큰 팬이고 지금까지 나는 너무 많은 두통을주는 문제가 발생하지 않았습니다.
답변
2020 년 4 월 업데이트 :
이 문제는 최신 React 16.13.1에서 수정 된 것으로 보입니다 ( 이 샌드 박스 예 참조) . 이것을 지적 해 준 @abernier에게 감사합니다.
나는 약간의 연구를 해왔고 중요한 한 가지 차이점을 발견했다.
React는 비동기 라이프 사이클 방법의 오류를 처리하지 않습니다.
따라서 다음과 같이 작성하면
componentDidMount()
{
throw new Error('I crashed!');
}
그러면 귀하의 오류가 오류 경계에 오류 를 처리하여 우아한 메시지를 표시 할 수 있습니다.
다음과 같이 코드를 변경하면 :
async componentDidMount()
{
throw new Error('I crashed!');
}
이것은 이것과 같습니다 :
componentDidMount()
{
return Promise.reject(new Error('I crashed!'));
}
그때 오류가 자동으로 삼켜 질 것입니다 집니다. 부끄러운 줄 알아
그렇다면 어떻게 오류를 처리합니까? 유일한 방법은 다음과 같이 명시 적으로 잡는 것 같습니다.
async componentDidMount()
{
try
{
await myAsyncFunction();
}
catch(error)
{
//...
}
}
또는 이와 같이 :
componentDidMount()
{
myAsyncFunction()
.catch(()=>
{
//...
});
}
여전히 오류가 오류 경계에 도달하기를 원한다면 다음 트릭을 생각할 수 있습니다.
- 오류를 잡아서 오류 처리기가 구성 요소 상태를 변경하게합니다.
- 상태가 오류를 나타내는 경우
render
메소드 에서 오류를 처리하십시오.
예:
class BuggyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
}
buggyAsyncfunction(){ return Promise.reject(new Error('I crashed async!'));}
async componentDidMount() {
try
{
await this.buggyAsyncfunction();
}
catch(error)
{
this.setState({error: error});
}
}
render() {
if(this.state.error)
throw this.state.error;
return <h1>I am OK</h1>;
}
}
답변
귀하의 코드는 훌륭하고 읽을 수 있습니다. 이 Dale Jefferson의 기사 에서 비동기 componentDidMount
예제 를 보여주고 실제로 잘 보입니다.
그러나 어떤 사람들은 코드를 읽는 사람이 React가 반환 된 약속으로 무언가를한다고 가정 할 수 있습니다.
따라서이 코드의 해석과 그것이 좋은 습관인지 아닌지는 매우 개인적인 것입니다.
다른 솔루션을 원한다면 promises를 사용할 수 있습니다 . 예를 들면 다음과 같습니다.
componentDidMount() {
fetch(this.getAuth())
.then(auth => {
if (auth) this.checkAuth(auth)
})
}
답변
키워드 componentDidMount
없이 사용 async
하면 의사는 다음과 같이 말합니다.
componentDidMount ()에서 즉시 setState ()를 호출 할 수 있습니다. 추가 렌더링을 트리거하지만 브라우저가 화면을 업데이트하기 전에 발생합니다.
사용 async componentDidMount
하면이 기능을 잃게됩니다. 브라우저가 화면을 업데이트 한 후에 다른 렌더링이 발생합니다. 그러나 imo, 데이터 가져 오기와 같은 비동기 사용을 생각하고 있다면 브라우저가 화면을 두 번 업데이트하는 것을 피할 수 없습니다. 다른 세계에서는 브라우저가 화면을 업데이트하기 전에 componentDidMount를 일시 중지 할 수 없습니다
답변
최신 정보:
(내 빌드 : React 16, Webpack 4, Babel 7) :
Babel 7을 사용하면 다음을 발견 할 수 있습니다.
이 패턴을 사용하여 …
async componentDidMount() {
try {
const res = await fetch(config.discover.url);
const data = await res.json();
console.log(data);
} catch(e) {
console.error(e);
}
}
다음과 같은 오류가 발생합니다 …
잡히지 않은 ReferenceError : regeneratorRuntime이 정의되지 않았습니다
이 경우 babel-plugin-transform-runtime 을 설치해야 합니다.
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
어떤 이유로 위의 패키지 (babel-plugin-transform-runtime)를 설치하지 않으려면 Promise 패턴을 고수하고 싶을 것입니다 …
componentDidMount() {
fetch(config.discover.url)
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(err => console.error(err));
}
답변
당신이하고있는 일을 아는 한 괜찮습니다. 그러나 async componentDidMount()
실행 후 componentWillUnmount
구성 요소가 마운트 해제 된 후에도 계속 실행될 수 있으므로 혼동 될 수 있습니다 .
내부에서 동기 및 비동기 작업을 모두 시작할 수도 있습니다 componentDidMount
. componentDidMount
비동기 인 경우 모든 동기 코드를 첫 번째 앞에 두어야합니다 await
. 첫 번째 코드 await
가 동기식으로 실행 되기 전에 누군가에게 분명하지 않을 수 있습니다 . 이 경우 아마도 componentDidMount
동기를 유지 하지만 sync 및 async 메서드를 호출해야합니다.
당신이 선택하든 async componentDidMount()
동기 대 componentDidMount()
호출 async
방법, 당신은 당신이 아직 구성 요소 마운트 해제를 실행중인 모든 청취자 또는 비동기 방법을 정리해야한다.
답변
실제로 React가 레거시 라이프 사이클 메소드 (componentWillMount, componentWillReceiveProps, componentWillUpdate)에서 비동기 렌더링으로 이동함에 따라 ComponentDidMount의 비동기 로딩이 권장되는 설계 패턴 입니다.
이 블로그 게시물은 이것이 왜 안전한지 설명하고 ComponentDidMount에서 비동기 로딩을위한 예제를 제공하는 데 매우 도움이됩니다.
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
