async componentDidMount () 사용이 좋은가요?
componentDidMount()
React Native에서 비동기 함수로 사용 하는 것이 좋은가요? 아니면 피해야하나요?
AsyncStorage
구성 요소가 마운트 될 때 정보를 얻어야 하지만이를 가능하게하는 유일한 방법은 componentDidMount()
함수를 비 동기화하는 것입니다.
async componentDidMount() {
let auth = await this.getAuth();
if (auth)
this.checkAuth(auth);
}
그것에 문제가 있고이 문제에 대한 다른 해결책이 있습니까?
차이점을 지적하고 그것이 어떻게 문제를 일으킬 수 있는지 결정하는 것으로 시작합시다.
다음은 비동기 및 "동기" 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이 다시 업데이트되며, 그 시간에는 이전 사용자와 이전 질문이 포함됩니다. 결과는 사용자에게도 표시됩니다.
=> method async
와 함께 사용 하는 것은 꽤 안전합니다 (100 % 정도는 모르겠습니다) componentDidMount()
. 나는 그것의 열렬한 팬이고 지금까지 나에게 너무 많은 두통을주는 어떤 문제도 만나지 않았다.
귀하의 코드는 훌륭하고 나에게 매우 읽기 쉽습니다. 이 Dale Jefferson의 기사 에서 비동기 componentDidMount
예제 를 보여주고 정말보기에도 좋습니다.
그러나 어떤 사람들은 코드를 읽는 사람이 React가 반환 된 promise로 무언가를한다고 가정 할 수 있다고 말합니다.
따라서이 코드의 해석과 그것이 좋은 관행인지 아닌지는 매우 개인적인 것입니다.
다른 솔루션을 원한다면 promise를 사용할 수 있습니다 . 예를 들면 :
componentDidMount() {
fetch(this.getAuth())
.then(auth => {
if (auth) this.checkAuth(auth)
})
}
키워드 componentDidMount
없이 사용할 때 async
문서는 다음과 같이 말합니다.
You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen.
If you use async componentDidMount
you will loose this ability: another render will happen AFTER the browser update the screen. But imo, if you are thinking about using async, such as fetching data, you can not avoid the browser will update the screen twice. In another world, it is not possible to PAUSE componentDidMount before browser update the screen
I think it's fine as long as you know what you're doing. But it can be confusing because async componentDidMount()
can still be running after componentWillUnmount
has run and the component has unmounted.
You may also want to start both synchronous and asynchronous tasks inside componentDidMount
. If componentDidMount
was async, you would have to put all the synchronous code before the first await
. It might not be obvious to someone that the code before the first await
runs synchronously. In this case, I would probably keep componentDidMount
synchronous but have it call sync and async methods.
Whether you choose async componentDidMount()
vs sync componentDidMount()
calling async
methods, you have to make sure you clean up any listeners or async methods that may still be running when the component unmounts.
Actually, async loading in ComponentDidMount is a recommended design pattern as React moves away from legacy lifecycle methods (componentWillMount, componentWillReceiveProps, componentWillUpdate) and on to Async Rendering.
This blog post is very helpful in explaining why this is safe and providing examples for async loading in ComponentDidMount:
https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html
I have made some research, and I have found one important difference: React does not process errors from async lifecycle methods.
So, if you write something like this:
componentDidMount()
{
throw new Error('I crashed!');
}
then your error will be caught by the error boundry, and you can process it and display a graceful message.
If we change the code like this:
async componentDidMount()
{
throw new Error('I crashed!');
}
which is equivalent to this:
componentDidMount()
{
return Promise.reject(new Error('I crashed!'));
}
then your error will be silently swallowed. Shame on you, React...
So, how do we process errors than? The only way seems to be explicit catch like this:
async componentDidMount()
{
try
{
await myAsyncFunction();
}
catch(error)
{
//...
}
}
or like this:
componentDidMount()
{
myAsyncFunction()
.catch(()=>
{
//...
});
}
If we still want our error rich the error boundary, I can think about the following trick:
- Catch the error, make the error handler change the component state
- If the state indicates an error, throw it from the
render
method.
Example:
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>;
}
}
Update:
(My build: React 16, Webpack 4, Babel 7):
When using Babel 7 you'll discover:
Using this pattern...
async componentDidMount() {
try {
const res = await fetch(config.discover.url);
const data = await res.json();
console.log(data);
} catch(e) {
console.error(e);
}
}
you will run into the following error...
Uncaught ReferenceError: regeneratorRuntime is not defined
In this case you will need to install babel-plugin-transform-runtime
https://babeljs.io/docs/en/babel-plugin-transform-runtime.html
If for some reason you do not wish to install the above package (babel-plugin-transform-runtime) then you will want to stick to the Promise pattern...
componentDidMount() {
fetch(config.discover.url)
.then(res => res.json())
.then(data => {
console.log(data);
})
.catch(err => console.error(err));
}
참고URL : https://stackoverflow.com/questions/47970276/is-using-async-componentdidmount-good
'program tip' 카테고리의 다른 글
HttpClient에서 await를 사용한 비동기 호출이 반환되지 않음 (0) | 2020.09.10 |
---|---|
HTML5 숫자 입력-항상 소수점 이하 2 자리 표시 (0) | 2020.09.10 |
빈 배열 항목을 건너 뛰면서 배열을 내파하려면 어떻게해야합니까? (0) | 2020.09.09 |
인간 친화적 인 상대 날짜 형식을위한 자바 스크립트 라이브러리 (0) | 2020.09.09 |
Android 용 로컬 이미지 캐싱 솔루션 : Square Picasso, Universal Image Loader, Glide, Fresco? (0) | 2020.09.09 |