Angular 수명 주기 후크를 사용하여 가져올 때 렌더링
21811 단어 webdevangulartypescriptjavascript
데이터를 가져 오는 중
먼저 앱에 표시할 데이터가 필요합니다. HTTP를 통해 할 일을 가져오는 서비스를 정의합니다.
const endpoint = "https://jsonplaceholder.typicode.com/todos"
@Injectable({ providedIn: "root" })
class TodosResource implements Fetchable<Todo[]> {
fetch(userId: number) {
return this.http.get(endpoint, {
params: { userId }
})
}
constructor(private http: HttpClient) {}
}
가져오기 함수 자체는 관찰 가능 항목을 반환할 필요가 없습니다. 약속과 같은 관찰 가능한 입력을 쉽게 반환할 수 있습니다. 모든 리소스가 이
Fetchable
인터페이스를 준수하도록 할 것입니다.현재 이것은 일반적인 Angular 서비스입니다. 나중에 다시 다루겠습니다.
리소스 인터페이스
기본적으로 리소스는 다음 두 가지 작업을 수행할 수 있습니다.
interface Resource<T extends Fetchable<any>> {
fetch(...params: FetchParams<T>): any
read(): FetchType<T> | undefined
}
가져오기 일부 데이터를 가져오도록 리소스에 지시합니다. 이는 HTTP 또는 GraphQL 엔드포인트, 웹소켓 또는 다른 비동기 소스에서 올 수 있습니다.
읽기 리소스의 현재 값을 읽으려고 시도합니다. 값이 아직 도착하지 않았기 때문에
undefined
일 수 있습니다.이 인터페이스를 정의하면 이를 구현하는 클래스를 작성할 수 있습니다.
구현
아래 예는 간결함을 위해 잘렸습니다. 보다 구체적인 예는 다음과 같습니다found here.
import { EMPTY, from, Subscription } from "rxjs"
export class ResourceImpl<T extends Fetchable>
implements Resource<T> {
value?: FetchType<T>
params: any
subscription: Subscription
state: string
next(value: FetchType<T>) {
this.value = value
this.state = "active"
this.changeDetectorRef.markForCheck()
}
read(): FetchType<T> | undefined {
if (this.state === "initial") {
this.connect()
}
return this.value
}
fetch(...params: FetchParams<T>) {
this.params = params
if (this.state !== "initial") {
this.connect()
}
}
connect() {
const source = this.fetchable.fetch(...this.params)
this.state = "pending"
this.unsubscribe()
this.subscription = from(source).subscribe(this)
}
unsubscribe() {
this.subscription.unsubscribe()
}
constructor(
private fetchable: T,
private changeDetectorRef: ChangeDetectorRef
) {
this.source = EMPTY
this.subscription = Subscription.EMPTY
this.state = "initial"
}
}
리소스는 생성자에 삽입된
fetchable
개체에 실제 데이터 가져오기 논리를 위임합니다. 리소스는 읽을 때 항상 최신 값을 반환합니다.또한 초기 상태에 있는 경우 데이터를 즉시 가져오지 않는다는 것을 알 수 있습니다. 첫 번째 가져오기를 위해
read
가 호출될 때까지 기다립니다. 이는 컴포넌트가 처음 마운트될 때 불필요한 가져오기를 방지하기 위해 필요합니다.리소스 관리에 도움이 되는 다른 서비스도 작성해 보겠습니다.
import {
Injectable,
InjectFlags,
Injector,
ChangeDetectorRef
} from "@angular/core"
@Injectable()
export class ResourceManager {
private cache: Map<any, ResourceImpl<Fetchable>>
get<T extends Fetchable>(token: Type<T>): Resource<T> {
if (this.cache.has(token)) {
return this.cache.get(token)!
}
const fetchable = this.injector.get(token)
const changeDetectorRef = this.injector
.get(ChangeDetectorRef, undefined, InjectFlags.Self)
const resource = new ResourceImpl(
fetchable,
changeDetectorRef
)
this.cache.set(token, resource)
return resource
}
ngOnDestroy() {
for (const resource of this.cache.values()) {
resource.unsubscribe()
}
}
constructor(private injector: Injector) {
this.cache = new Map()
}
}
용법
리소스 서비스를 구축했으므로 이제 실제로 살펴보겠습니다!
<!-- todos.component.html -->
<div *ngFor="let todo of todos">
<input type="checkbox" [value]="todo.complete" readonly />
<span>{{ todo.title }}</span>
</div>
<button (click)="loadNextUser()">
Next user
</button>
import {
Component,
OnChanges,
DoCheck,
Input,
ChangeDetectionStrategy
} from "@angular/core"
import {
Resource,
ResourceManager
} from "./resource-manager.service"
import { Todos, TodosResource } from "./todos.resource"
@Component({
selector: "todos",
templateUrl: "./todos.component.html",
providers: [ResourceManager],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TodosComponent implements OnChanges, DoCheck {
@Input()
userId: number
resource: Resource<TodosResource>
todos?: Todos[]
ngOnChanges() {
this.loadNextUser(this.userId)
}
ngDoCheck() {
this.todos = this.resource.read()
}
loadNextUser(userId = this.userId++) {
this.resource.fetch(userId)
}
constructor(manager: ResourceManager) {
this.userId = 1
this.resource = manager.get(TodosResource)
this.resource.fetch(this.userId)
}
}
마지막으로
fetch
가 두 번 호출되는 것을 볼 수 있습니다. 생성자에서 한 번 그리고 ngOnChanges
수명 주기 후크 동안 다시 한 번. 그렇기 때문에 처음으로 데이터 소스를 구독하기 전에 read
를 기다려야 합니다.모든 마법은
ngDoCheck
에서 발생합니다. 일반적으로 이 후크를 사용하는 것은 좋지 않지만 가져올 때 렌더링하는 데는 완벽합니다! read
함수는 단순히 리소스의 현재 값을 반환하고 이를 todos
에 할당합니다. 마지막 읽기 이후 리소스가 변경되지 않은 경우 no-op입니다.이것이 작동하는 이유가 궁금하다면
next
의 ResourceImpl
함수로 다시 스크롤하십시오.next() {
// ...
this.changeDetectorRef.markForCheck()
}
이는 자원이 새 값을 수신할 때마다 보기를 더티로 표시하고 결국
ngDoCheck
를 트리거합니다. 리소스가 동기 값을 매우 빠르게 생성하는 경우 추가 변경 감지 호출도 방지합니다. 정돈된!요약
Angular의 변경 감지 메커니즘을 활용하여 가져올 때 렌더링할 수 있습니다. 이를 통해 뷰를 차단하지 않고 여러 데이터 스트림을 병렬로 쉽게 로드할 수 있으며, 조금 더 노력하면 데이터가 로드되는 동안 사용자에게 멋진 폴백을 보여줄 수도 있습니다. 접근 방식은 데이터에 구애받지 않으며 기존 코드를 보완해야 합니다.
즐거운 코딩하세요!
Reference
이 문제에 관하여(Angular 수명 주기 후크를 사용하여 가져올 때 렌더링), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/antischematic/render-as-you-fetch-with-angular-lifecycle-hooks-396i텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)