Reusable and recyclable NativeScript views
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Accessibilité débutants
- 25/100
- Type d'issue
- Fonctionnalité
- Clarté
- À clarifier
- Activité
- À l'abandon
- Stack technique
- android, ios, typescript
- Domaine
- mobile-dev
Piste de recherche
Commencez par lire le comportement de suppression des native views introduit dans NativeScript PR 3912 et reproduisez les cas de detach/attach dans les playgrounds TypeScript et Angular liés. Le travail serait terminé lorsqu’un cycle de vie défini pour les vues réutilisables préserverait les native views lors du detach et permettrait de les attacher à un autre parent sans les recréer.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Is your feature request related to a problem? Please describe.
Removing a NativeScript view from the visualtree results in all native views being disposed on Android. On iOS, some native views are not disposed, but their delegates are. This behavior seems to come from https://github.com/NativeScript/NativeScript/pull/3912 but I haven't found an explanation for why it is that way.
Since the view is destroyed, there is no way to do, for example:
const parent1 = stack1;
const parent2 = stack2;
const st = new StackLayout();
const bt = new Button()
st.addChild(bt);
parent1.addChild(st);
// st.android != null
parent1.removeChild(st);
// st.android == null
parent2.addChild(st);
// st.android != null
Without the view being destroyed and created again.
This also makes hard to use some plugins like nativescript-popup. We've tried creating an angular template and passing the NS views to the plugin, but once we detached the view from it's parent, the native views became null and the popup was empty. Our workaround was to manually use the native views that were created and set view.parent = null otherwise the app would crash when closed.
Describe the solution you'd like
NativeScript views could be reusable:
const parent1 = stack1;
const parent2 = stack2;
const st = new StackLayout();
st.reusable = true;
const bt = new Button()
st.addChild(bt);
parent1.addChild(st);
const native = st.android;
parent1.removeChild(st);
native === st.android // true
parent2.addChild(st);
native === st.android // true
This is different from https://github.com/NativeScript/NativeScript/issues/4189, since we're not just reusing the native views, but the whole NS view, so no properties have to be reset. Maybe an additional method (like view.inflate()) could be provided to inflate views without the need to attach to the "dom".
Additional context
I've only used core and angular flavors, so I'll contextualize it using them:
Angular/Vue/React/etc flavors of nativescript would create all their views as reusable. The angular renderer has destroyNode method that is unimplemented by nativescript-angular because the core already destroys the view when it's detached. This method is called when the view is not being used anymore, so the view can be safely detached and reused. I'm sure the other frameworks have similar approaches.
This necessity came up when I was starting to develop a recyclerview plugin with shared pools (which is possible natively, no need for this PR) and general use of nativescript-popup and I stumbled upon my views being destroyed whenever I tried to detach them.
Here's a playground of the current behavior: https://play.nativescript.org/?template=play-tsc&id=eorFFE&v=6
Here's what happens when we try detaching and attaching: https://play.nativescript.org/?template=play-ng&id=mXwdnl
Ideally, "create native view" should only output once for each label created by "Create Views" and none for "Move Views".
Partially inspired by: https://hackernoon.com/react-native-listview-performance-revisited-recycling-without-the-bridge-c4f62d18c7dd?gi=87e16d79933e
Use cases
Custom reusable heavy views/view tree in the core
Allows you to reuse a view or view tree anywhere. Examples: footer that is used in almost every screen only needs to instanced once. Same view pool for multiple ListViews. A conditional view that may be added or not to a ListView item (the current best practice is instantiate all views and set the visibility property, or using multiple templates, potentially increasing memory usage).
// viewrecyler.ts
export class ViewRecycler {
viewPool = [];
availableViews = [];
prefetch = 5;
constructor() {
for (let i = 0; i < this.prefetch; i++) {
this.generateReusableView();
}
}
generateReusableView() {
const view = new HeavyView(); // HeavyView could be a whole view tree
view.reusable = true;
view.inflate(); // force creation, we're prefetching.
this.viewPool.push(view);
this.availableViews.push(view);
return view;
}
getView() {
if (this.availableViews.length === 0) {
this.generateReusableView(); // if none available, generate a new one
}
return this.availableViews.pop();
}
storeView(detachedView: HeavyView) {
this.availableViews.push(detachedView);
}
}
export const viewRecycler = new ViewRecycler();
// page.ts
let recyclableView;
function navigatedTo() {
const container = getViewById(page, "viewcontainer");
recyclableView = viewRecycler.getView();
container.addChild(recyclableView);
}
function navigatingFrom() {
if (recyclableView) {
recyclableView.parent.removeChild(recyclableView);
viewRecycler.storeView(recyclableView);
recyclableView = null;
}
}
It's up to the developer to set/reset view properties. In the example above, all properties must be set on recyclableView = viewRecycler.getView();, or reset on viewRecycler.storeView(recyclableView);. When too many properties are being reset each time (defeating the purpose of recycling), it's recommended to add a new view pool.
ngFor/Repeater
What could be accomplished with this:
<Button *ngFor="let item of item;"></Button>
This is already possible, but every time you swap something, angular uses detach and insert, meaning you get lag. Workaround: use trackBy using index.
<Button *ngReusableFor="let item of items; uniqueKey:'myForKey'"></Button>
<Button *ngReusableFor="let item of items2; uniqueKey:'myForKey'"></Button>
ngReusableFor would have a service that stores views in myForKey. No matter how many items you add/remove from items and item2, the same views would be reused in both of them. caution: the same template has to be used for both fors.
Global templates
My favorite use case.
<GlobalTemplates>
<ng-template templateKey="reusablecard" let-item="item">
<CardView>
<StackLayout>
<Label text="item.title"></Label>
<Label text="item.content"></Label>
</StackLayout>
</CardView>
</ng-template>
</GlobalTemplates>
...
<!-- use inside a listview, ngfor, or any html -->
<ReusableTemplate key="reusablecard" context="item"></ReusableTemplate>
Every time you'd use that template, it'd be a recycled instance from somewhere in the app. You could have horizontal listviews inside a vertical listview and they all share the same pool of recycled components. You could also configure some prefetching (create 5 cards when the app starts and just use them over and over).
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
- Langage dominant
- TypeScript
- Étoiles
- 25.7k
- Forks
- 1.7k
- Merge moyen
- 1 j 5 h
- PR mergées (30 j)
- 35
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de NativeScript/NativeScript
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
NativeScript/NativeScript#11068 ·
-
bug-pending-triage
Difficulté 3/5 1-2 jours Accessibilité débutants 66/100
NativeScript/NativeScript#11436 ·
-
Difficulté 4/5 3-5 jours Accessibilité débutants 45/100
NativeScript/NativeScript#11421 ·
-
bug-pending-triage
Difficulté 3/5 1-2 jours Accessibilité débutants 52/100
NativeScript/NativeScript#11415 ·
-
bug-pending-triage
Difficulté 3/5 1-2 jours Accessibilité débutants 48/100
NativeScript/NativeScript#11374 ·
Toutes les issues de NativeScript/NativeScript
Issues similaires
-
comp/dashboard P3 type/bug
Difficulté 2/5 1-3 heures Accessibilité débutants 86/100
NousResearch/hermes-agent#117722 ·
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P3
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulté 1/5 Moins d'une heure Accessibilité débutants 76/100
-
code-quality refactoring
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
github/gh-aw-firewall#8816 ·
-
integration:quickjs org:external priority:backlog topic:code-interpreter topic:middleware type:feature
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
langchain-ai/deepagents#6450 ·