I React er bruken av useEffect-hooken essensiell for å håndtere "sideeffekter" i komponentene våre. Funksjonelle komponenter har i utgangspunktet én oppgave: å returnere JSX-innhold for rendering. Hvis komponenten trenger å utføre andre oppgaver, som for eksempel å hente data fra et API, skal dette håndteres innenfor useEffect. En feil som ofte gjøres, er å plassere API-kallene direkte i komponenten, noe som kan føre til løpsbetingelser og andre vanskelige feil som er vanskelig å rette.

La oss se på et eksempel som bruker useEffect for å hente data fra et API:

javascript
function App() {
const [id, setId] = React.useState("loading...");
const [name, setName] = React.useState("loading...");
const fetchUser = React.useCallback(() => {
return new Promise((resolve) => {
setTimeout(() => { resolve({ id: 1, name: "Mike" }); }, 1000); }); }, []); React.useEffect(() => { fetchUser().then((user) => { setId(user.id); setName(user.name); }); }); return ( <> ID: {id} Name: {name} </> ); }

I dette eksemplet er fetchUser en funksjon som returnerer et løfte (promise), som etter en forsinkelse på ett sekund, returnerer et objekt med ID og navn. Denne funksjonen er definert ved hjelp av useCallback, som memoiserer funksjonen for å unngå at den blir gjenopprettet på hver render. Når komponenten renderes på nytt, vil ikke fetchUser-funksjonen bli opprettet på nytt, noe som forbedrer ytelsen.

useEffect-hooken brukes for å utføre fetchUser når komponenten er ferdig med å rendre. Det er viktig å merke seg at useEffect ikke forstyrrer Reacts interne prosesser og gjør at sideeffektene kjøres etter at den aktuelle rendering er fullført.

Denne typen sideeffekt er ikke bare nyttig for API-kall, men kan også håndtere andre asynkrone operasjoner som datahenting, oppdatering av DOM eller eksterne hendelser. Det er imidlertid viktig å være oppmerksom på at når komponenten fjernes, bør vi rydde opp etter eventuelle ufullførte sideeffekter. Dette gjelder særlig for operasjoner som bruker tid, som f.eks. tidsintervall eller API-anrop.

En annen viktig aspekt ved bruk av useEffect er håndtering av avbrutte API-kall når brukeren navigerer bort fra komponenten før svaret fra API-et er mottatt. Her er et eksempel på en timer-komponent som viser hvordan vi kan rydde opp etter en sideeffekt når komponenten fjernes:

javascript
function Timer() {
const [timer, setTimer] = React.useState(100);
React.useEffect(() => { const interval = setInterval(() => { setTimer((prevTimer) => (prevTimer === 0 ? 0 : prevTimer - 1)); }, 1000); return () => { clearInterval(interval); }; }, []);
return <div>Timer: {timer}</div>;
}

I dette eksemplet setter useEffect opp en tidsintervall som oppdaterer timerens tilstand hvert sekund. Når komponenten fjernes, vil funksjonen som returneres fra useEffect bli kalt for å rydde opp ved å fjerne tidsintervallen. Dette er en viktig del av minnehåndteringen, da uavbrutte prosesser kan føre til minnelekkasjer.

I applikasjonen vår kan vi også bruke en enkel funksjonalitet for å vise og skjule Timer-komponenten basert på en show-tilstand:

javascript
const ShowHideTimer = ({ show }) => (show ? <Timer /> : null);
function App() { const [show, setShow] = React.useState(false); return ( <> <button onClick={() => setShow(!show)}> {show ? "Hide Timer" : "Show Timer"} </button> <ShowHideTimer show={show} /> </> ); }

Når Timer-komponenten vises, starter useEffect en tidsintervall, og når komponenten fjernes, blir tidsintervallen stoppet. Dette forhindrer at nye lyttere legges til ved hver render, som kan føre til minnelekkasjer over tid.

Når vi kombinerer useState, useEffect, og useCallback, får vi en kraftig mekanisme for å håndtere tilstander og sideeffekter i React-applikasjoner. Men det er viktig å merke seg at vi kan kontrollere når effektene skal kjøres, for eksempel kun når bestemte tilstander endres eller etter første rendering. Dette gir utvikleren kontroll over når og hvordan sideeffekter utføres, og kan optimalisere applikasjonens ytelse og stabilitet.

I tillegg til det som er beskrevet, er det viktig å forstå at React ikke nødvendigvis "rydder opp" automatisk i alle tilfeller. Hvis en komponent gjør et API-kall og brukeren navigerer bort før svaret er mottatt, bør du ha et system på plass for å annullere disse forespørslene. Dette kan gjøres med hjelp av abortkontroller, som kan implementeres for å hindre at unødvendige API-kall fullføres når de ikke lenger er relevante for komponentens nåværende tilstand.

Ved å bruke useEffect riktig, kan vi unngå vanlige problemer som forsinkede dataoppdateringer, minnelekkasjer og ineffektive rendering-prosesser, og dermed bygge mer effektive og pålitelige applikasjoner.

Hvordan effektivt hente data fra en server med GraphQL og Apollo Client

I dagens webapplikasjoner er det avgjørende å kunne hente data fra servere på en effektiv og optimalisert måte. Dette kan innebære å redusere mengden data som sendes, og sikre raskere datainnhenting, noe som er viktig for både ytelse og brukeropplevelse. En av de mest moderne tilnærmingene for å hente data fra en server er ved hjelp av GraphQL, sammen med biblioteker som Apollo Client, som gir funksjonalitet som ligner på React Query, men er spesifikt designet for GraphQL-spørringer. I denne sammenhengen vil vi se nærmere på hvordan GraphQL og Apollo Client kan brukes til å hente data på en effektiv måte.

For å komme i gang med Apollo Client, er det første trinnet å installere nødvendige avhengigheter. Dette kan gjøres enkelt via npm med følgende kommando:

bash
npm install @apollo/client graphql

Når avhengighetene er installert, er det neste steget å sette opp Apollo Client. For dette eksempelet bruker vi GitHub GraphQL API, og må spesifisere serverens URL, caching-innstillinger og autentisering. Dette kan gjøres ved å legge til følgende konfigurasjon:

javascript
const client = new ApolloClient({ uri: "https://api.github.com/graphql", cache: new InMemoryCache(), headers: { Authorization: 'Bearer YOUR_PAT', // Sett inn din GitHub personlige tilgangstoken }, });

Når dette er på plass, kan Apollo Client brukes til å hente data fra GitHub API ved hjelp av GraphQL-spørringer. For å illustrere hvordan dette kan gjøres, antar vi at vi ønsker å hente ut spesifik informasjon om en GitHub-bruker. Vår GraphQL-spørring kan se slik ut:

javascript
const GET_GITHUB_USER = gql`
query GetGithubUser($username: String!) {
user(login: $username) {
login id avatarUrl bio name company location
} } `;

Denne spørringen henter ut informasjon om GitHub-brukeren basert på brukernavnet som sendes som variabel. I komponenten som håndterer datainnhentingen, kan Apollo Client brukes til å gjøre spørringen og håndtere tilstander som lasting og feil:

javascript
function App() { const { data, loading, error } = useQuery(GET_GITHUB_USER, { variables: { username: "sakhnyuk" }, });
if (loading) return <div>Loading...</div>;
if (error) return <div>Error fetching data</div>; const user = data.user; return ( <div>
<img src={user.avatarUrl} alt={user.login} />
<p>{user.name}</p> </div> ); }

Her håndteres tilstander for lasting og feil, og dataene fra serveren vises på skjermen når de er hentet. Ved å bruke verktøy som Chrome DevTools kan man inspisere nettverksforespørslene som sendes til serveren, og bekrefte at kun de nødvendige feltene er hentet, noe som viser hvordan GraphQL kan bidra til å redusere mengden data som overføres.

En annen fordel med GraphQL er dens fleksibilitet. Ved å endre spørringen kan vi hente akkurat de dataene vi trenger, og dermed unngå å overføre unødvendig informasjon. Dette gir en mer effektiv og målrettet måte å hente data på, som er spesielt viktig i applikasjoner som skal håndtere store mengder informasjon.

Ved å implementere GraphQL sammen med Apollo Client kan utviklere bygge applikasjoner som henter data på en rask, effektiv og skalerbar måte. Denne tilnærmingen gir mulighet for å skape dynamiske og datadrevne brukeropplevelser, og er ideell for applikasjoner som trenger å hente og vise oppdatert informasjon i sanntid, som for eksempel sosiale medieplattformer eller e-handelsnettsteder.

I tillegg til de tekniske aspektene, er det viktig å forstå at bruken av GraphQL krever en god struktur på både server- og klientsiden. På serversiden må API-et være designet for å støtte GraphQL-spørringer, og på klientsiden må man være forberedt på å håndtere flere mulige tilstander som lasting, feil, og suksess.

En annen viktig betraktning er hvordan data caching fungerer. Apollo Client bruker et intern minnecache, som gjør at tidligere hentede data kan gjenbrukes uten å måtte gjøre nye nettverksforespørsler. Dette reduserer belastningen på serveren og forbedrer ytelsen for brukeren.

GraphQL tilbyr en betydelig forbedring i forhold til tradisjonelle REST API-er ved at den lar klienten spesifisere nøyaktig hva den trenger, og dermed redusere både overførings- og behandlingskostnader. Det er imidlertid viktig å merke seg at implementeringen av GraphQL kan være mer kompleks enn vanlige REST-API-er, og krever god forståelse både av serverens API-struktur og hvordan man håndterer spørringer på klientsiden.

Så, i tillegg til de tekniske ferdighetene man lærer i implementeringen, er det viktig å ha en klar plan for hvordan applikasjonen skal håndtere dataflyt, caching, og feil. Det er også nødvendig å ha en forståelse for hvordan GraphQL skiller seg fra andre tilnærminger som REST og hvordan man kan dra nytte av denne fleksibiliteten for å bygge mer effektive applikasjoner.

Hvordan teste enhet i ReactJS: Mocks og testing av komponenter

Unit testing er en kritisk del av programvareutvikling, da det sikrer at individuelle enheter eller funksjoner i koden fungerer som forventet. I React-applikasjoner er testing spesielt viktig, ettersom React-komponenter ofte er ansvarlige for å håndtere brukerinteraksjon og UI-oppdateringer. I denne delen av boken fokuserer vi på hvordan vi kan sette opp og skrive enhetstester for React-komponenter, samt hvordan vi kan bruke mock-funksjoner for å isolere komponentenes logikk fra eksterne avhengigheter.

For å begynne med testing i React, er det viktig å forstå hvordan React-komponenter fungerer. En React-komponent er i hovedsak en funksjon som returnerer et DOM-element, som blir rendret på skjermen. I en enhetstest er vi interessert i å teste logikken og funksjonaliteten til disse komponentene, uavhengig av den faktiske nettleseren. For å gjøre dette bruker vi JSDOM, et bibliotek som simulerer et DOM-miljø i Node.js. React Testing Library fungerer sammen med JSDOM for å gjøre det enklere å rendere komponenter og samhandle med dem i testene.

La oss se på et enkelt eksempel på hvordan enhetstester kan skrives for React-komponenter ved å bruke React Testing Library og Vitest. Først må vi installere de nødvendige avhengighetene. Dette kan gjøres i et nytt Vite-prosjekt med følgende kommando:

bash
npm install --save-dev @testing-library/react @testing-library/jest-dom vitest jsdom

Etter at avhengighetene er installert, må vi sette opp miljøet for testing. Dette innebærer å konfigurere testbibliotekene slik at de fungerer sammen med Vitest. Vi lager en tests/setup.ts-fil som integrerer React Testing Library med Vitest:

typescript
import { expect, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react'; import * as matchers from "@testing-library/jest-dom/matchers"; expect.extend(matchers); afterEach(() => { cleanup(); });

I tillegg må vi oppdatere konfigurasjonsfilen vite.config.ts for å inkludere en spesiell testmiljøinnstilling:

typescript
test: {
globals: true, environment: "jsdom", setupFiles: "./tests/setup.ts", },

For å kunne bruke matchers fra React Testing Library i testene, legger vi til følgende i src/vite-env.d.ts:

typescript
import type { TestingLibraryMatchers } from "@testing-library/jest-dom/matchers"; declare global { namespace jest {
interface Matchers extends TestingLibraryMatchers {}
} }

Når miljøet er satt opp, kan vi begynne å skrive tester. La oss starte med en enkel test som sjekker om en komponent er rendret korrekt. Vi lager en enkel App-komponent som returnerer teksten "Hello world":

typescript
export function App() {
return <div>Hello world</div>;
}

Testen for denne komponenten kan se slik ut:

typescript
import { render, screen } from "@testing-library/react"; import { describe, it, expect } from "vitest"; import { App } from "./App"; describe("App", () => { it("should be in document", () => { render(<App />);
expect(screen.getByText("Hello world")).toBeInTheDocument();
}); });

Denne testen sjekker om teksten "Hello world" er til stede i dokumentet etter at komponenten er rendret. render-funksjonen fra React Testing Library rendrer komponenten til en virtuell DOM, og screen.getByText søker etter et element med den spesifikke teksten.

I en mer kompleks komponent kan vi for eksempel teste at et knappetrykk endrer komponentens tilstand. La oss lage en komponent som endrer stil på et element når det blir klikket:

typescript
export function ClassCheck() {
const [clicked, setClicked] = useState(false); return ( <button className={clicked ? "clicked" : ""} onClick={() => setClicked(!clicked)} > Click me </button> ); }

For å teste denne komponenten kan vi skrive en test som sjekker om klassen endres etter at knappen blir klikket:

typescript
import { render, screen, fireEvent } from "@testing-library/react";
import { ClassCheck } from "./ClassCheck";
describe("ClassCheck", () => { it("should add 'clicked' class when button is clicked", () => { render(<ClassCheck />); const button = screen.getByText("Click me"); fireEvent.click(button); expect(button).toHaveClass("clicked"); fireEvent.click(button); expect(button).not.toHaveClass("clicked"); }); });

Denne testen simulerer et knappetrykk med fireEvent.click, og deretter verifiserer vi om klassen "clicked" legges til eller fjernes som forventet.

En annen viktig del av testing i React er å håndtere eksterne avhengigheter, som API-forespørsler eller tredjepartsbiblioteker. I mange tilfeller vil en komponent hente data fra en server, og i slike tilfeller må vi mocke disse forespørslene for å isolere testene fra eksterne faktorer. En effektiv måte å gjøre dette på er å bruke Mock Service Worker (MSW), som lar oss simulere API-responser.

La oss se på et eksempel der vi mocker et API-kall til GitHub:

typescript
import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { describe, it, expect, beforeAll, afterEach, afterAll } from 'vitest'; const server = setupServer( http.get('https://api.github.com/users', () => { return HttpResponse.json({ firstName: 'Mikhail', lastName: 'Sakhniuk', }); }) ); describe('Mocked fetch', () => { beforeAll(() => server.listen()); afterEach(() => server.resetHandlers()); afterAll(() => server.close()); it('should return test data', async () => {
const response = await fetch('https://api.github.com/users');
expect(response.status).toBe(200);
expect(response.statusText).toBe('OK');
expect(await response.json()).toEqual({ firstName: 'Mikhail', lastName: 'Sakhniuk', }); }); });

Her setter vi opp en mock-server som simulerer et svar fra GitHub API. Testen sjekker deretter om vi mottar det forventede svaret fra den mockede API-forespørselen.

Enhetstesting i React er ikke bare et nyttig verktøy for å sikre at applikasjonen fungerer som forventet, men det gir også en struktur for å utvikle vedlikeholdbare og pålitelige applikasjoner. Når du skriver tester, er det viktig å fokusere på komponentenes logikk og ikke på implementasjonsdetaljer som kan endre seg over tid. Ved å mocke eksterne avhengigheter kan vi sikre at testene våre er isolerte og ikke påvirkes av faktorer som API-tilgjengelighet eller tredjepartsbibliotek.

Hvordan vise fremgang i applikasjoner med React Native

Å vise fremgang i en applikasjon er essensielt for å gi brukeren en følelse av kontroll over hva som skjer, spesielt når prosesser tar tid. Det finnes ulike måter å indikere fremgang på i React Native, og i denne sammenhengen ser vi på hvordan man kan implementere både uspesifikke indikatorer som spinner og spesifikke progresjonsindikatorer, som fremdriftslinjer og trinnindikatorer. Dette kan gjøres gjennom ulike komponenter og teknikker som er lett tilgjengelige i React Native-økosystemet.

En nyttig komponent for å vise et lastingsbilde er LoadingWrapper. Denne komponenten fungerer som et kapslingslag for en annen komponent, og håndterer visningen av en lastespinner til barnet er klart til å vises. Komponentens arbeidsflyt baseres på en useEffect-hook som setter en timer for å endre tilstanden fra lasting til ferdig. Denne løsningen er praktisk for å skjule ekstra logikk og gjør det enkelt å bruke samme komponent på flere skjermbilder. I en virkelig applikasjon kan man legge til flere props for å ha mer kontroll over lastingsstatusen, og dermed unngå å hardkode ventetiden.

Et vanlig problem med en enkel lastespinner er at brukeren ikke har en idé om hvor lang tid prosessen vil ta. Det er derfor viktig å bruke en progressindikator som gir et mål for hvor mye som er gjort, og hvor mye som gjenstår. Bruken av en fremdriftslinje (progress bar) gir brukeren en bedre opplevelse, da de kan følge utviklingen i sanntid. Det finnes flere bibliotek som kan hjelpe med dette, og et populært valg for React Native er react-native-progress.

I et eksempel for implementering av fremdriftsindikatorer, ser vi på komponenten ProgressBar. Denne komponenten tar et progress-prop, som representerer prosentandelen som er fullført, og gir både en fremdriftslinje og en tekst som indikerer prosentverdien. Dette er nyttig for å vise fremgang for operasjoner som kan ta variabel tid, som nedlastinger eller opplastinger.

I eksemplet bruker vi en enkel timer i useEffect-hooken for å simulere en prosess, der progressiv oppdatering skjer hvert hundrede sekund. Selv om man vanligvis ikke vil bruke simulert tid i en virkelig app, er det mange scenarier der det er verdifullt å vise progressen til brukeren. Eksempler på slike scenarier inkluderer filopplastinger, statistikkinnhenting, eller operasjoner med lang behandlingstid.

Progress barer er ikke bare nyttige for å vise generelle prosesser, men også for å vise spesifik fremgang gjennom flere trinn. En trinnvis progress bar kan hjelpe brukeren å forstå hvor de er i en flerstegsprosess. For eksempel kan et skjema deles opp i flere deler, og med hver fullførte del kan progresjonen oppdateres i en visuell indikator. Denne typen fremgangsbart system er spesielt nyttig i applikasjoner med flere skjermer, som guider brukeren gjennom prosesser som registrering, betaling eller opprettelse av innhold.

Når man implementerer en trinnvis fremdriftsindikator i React Native, er det nyttig å bruke createNativeStackNavigator til å definere navigasjonsstrukturen. Hver skjerm kan oppdatere progresjonsbaren ved hjelp av ruteindeksen i stakken, og på den måten vises progresjonen i forhold til den nåværende skjermens plass i stakken. Dette kan være svært nyttig for å vise trinnvis fremgang i prosesser som krever at brukeren fullfører et sett med oppgaver før de kan gå videre.

En viktig del av progresjonshåndtering er at man må være forsiktig med hvordan man presenterer informasjon om fremgang. Hvis progresjonen oppdateres for ofte eller uten nok visuell tydelighet, kan det føre til forvirring eller frustrasjon. Det er viktig å balansere hvor ofte fremdriften blir oppdatert med hvor mye informasjon brukeren faktisk trenger for å føle seg komfortabel.

En annen faktor å vurdere er ytelsen. Å oppdatere progresjonsindikatorer kontinuerlig kan føre til unødvendig belastning på systemet, spesielt på enhetenes mindre kraftige enheter. Derfor er det viktig å optimalisere bruken av fremdriftsindikatorer, slik at de ikke hindrer appens generelle ytelse.

I tillegg kan det være nyttig å gi brukeren mer kontroll over visningen av fremgang. I noen tilfeller kan det være fordelaktig å tillate brukeren å pause, avbryte eller få mer informasjon om hva som skjer underveis. Dette kan bidra til å redusere følelsen av usikkerhet som kan oppstå i løpet av lange ventetider.

Hvordan håndtere feilmeldinger og varsler i mobilapplikasjoner

I utviklingen av mobile applikasjoner er en av de viktigste aspektene å sørge for at brukeren får riktig informasjon når noe går galt. Dette kan variere fra en enkel feilmelding til mer komplekse interaksjoner som krever brukerens handling. I denne sammenhengen kan modale vinduer og varsler spille en avgjørende rolle for å formidle nødvendige beskjeder uten å forstyrre brukerens opplevelse mer enn nødvendig.

En vanlig måte å håndtere feilmeldinger på er gjennom modale vinduer som krever brukerens interaksjon før de kan lukkes. For eksempel kan en feilmelding som "Epic fail!" vises i et modalt vindu sammen med knapper som lar brukeren velge enten å fikse feilen eller ignorere den. Når du designer slike modalvinduer, er det viktig å merke seg at stilene for disse komponentene ofte kombineres i en array, der siste stil vanligvis overstyrer tidligere definerte stiler. Dette er nyttig når man skal håndtere konflikter mellom forskjellige stilattributter, som for eksempel bakgrunnsfarge, der siste definisjon vinner.

I mange tilfeller vil feilmeldingene kreve at brukeren tar en beslutning. Men det er også situasjoner hvor feilene er uopprettelige, og det eneste som kan gjøres, er å informere brukeren om situasjonen. I slike tilfeller kan en enkel varselmelding være tilstrekkelig, uten å kreve brukerens aktive deltakelse. Det er her passive varsler kommer inn i bildet, som ikke tvinger brukeren til å gjøre noe, men bare viser informasjon på en diskret måte.

En populær metode for å implementere slike passive varsler på Android-enheter er ved hjelp av Toast-komponenten, som også finnes for iOS gjennom tredjepartsbiblioteker som react-native-root-toast. En Toast er en liten melding som vises på skjermen i en kort periode og forsvinner automatisk, uten at brukeren må gjøre noe. Dette er ideelt for å vise meldinger som ikke nødvendigvis krever en umiddelbar handling, men likevel er viktig for brukerens forståelse.

For eksempel kan koden for å vise en Toast-segment på skjermen se slik ut:

javascript
export default function PassiveNotifications() {
return ( <Button onPress={() => { Toast.show("Something happened!", { duration: Toast.durations.LONG }); }} > Show Notification </Button> ); }

I tillegg til de enkle feilmeldingene og passive varslene finnes det også situasjoner hvor applikasjonen må vise at noe er i ferd med å skje, som når data hentes fra en server. Her er det vanlig å bruke modale skjermer med en aktivitetindikator som viser fremdriften. En aktivitetmodal kan vises mens en bakgrunnsprosess kjøres, og skjules når prosessen er ferdig. Et eksempel på hvordan dette kan implementeres er med en ActivityIndicator-komponent i React Native. Når et asynkront kall blir gjort, kan vi vise en modal med en indikasjon på at prosessen pågår, som for eksempel en "laster"-grafikk.

For å implementere en slik komponent, kan man bruke følgende kode:

javascript
type ActivityProps = { visible: boolean; size?: "small" | "large"; };
export default function Activity({ visible, size = "large" }: ActivityProps) {
return ( <Modal visible={visible} transparent={true}> <ActivityIndicator size={size} /> </Modal> ); }

I denne koden setter vi visible-propertien for å kontrollere om modalvinduet skal vises eller ikke, avhengig av om en prosess pågår. Det er viktig å merke seg at vi ikke introduserer en intern tilstand knyttet til løftet i denne komponenten, for å unngå unødvendig kompleksitet.

Som en praktisk implementasjon kan vi lage en applikasjon der en bruker klikker på en knapp som starter et simuleringsprosjekt, og under prosessen vises en aktivitetmodal:

javascript
export default function App() { const [fetching, setFetching] = useState(false);
const [promise, setPromise] = useState(Promise.resolve());
function onPress() { setPromise( new Promise((resolve) => setTimeout(resolve, 3000)).then(() => { setFetching(false); }) ); setFetching(true); } return ( <Button onPress={onPress}>Fetch Stuff...</Button> ); }

I eksemplet ovenfor blir en aktivitetmodal vist når en asynkron operasjon pågår. Dette kan være nyttig for å informere brukeren om at noe er i ferd med å skje, som nedlasting av data eller annen langvarig operasjon. Når operasjonen er ferdig, skjules modalen automatisk.

Det er viktig å merke seg at disse teknikkene ikke nødvendigvis gjelder for alle applikasjoner, og designvalg bør baseres på hvordan brukeren forventes å interagere med applikasjonen. I applikasjoner med høy grad av brukerengasjement kan det være mer hensiktsmessig å bruke modale vinduer for å få tilbakemeldinger, mens i applikasjoner med en mer passiv brukeropplevelse kan Toast- eller aktivitetsmodaler være bedre egnet.

Selv om modaler og varsler kan være effektive i å formidle informasjon, bør de brukes med forsiktighet. For mange intrusive varsler kan føre til frustrasjon hos brukeren, og en god balanse mellom nødvendige varsler og en ikke-påtrengende brukeropplevelse bør alltid opprettholdes.