React

ReactJS er et af de mest populære JavaScript-biblioteker til udvikling af mobil- og webapplikationer. Det er skabt af Facebook og bruger genanvendelige JavaScript-kodebidder kaldet komponenter til at opbygge brugergrænseflader (UI).

ReactJS er ikke et JavaScript-framework, men det er et kraftfuldt alternativ til frameworks som Angular og Vue. I stedet for at være ansvarlig for hele applikationens struktur, fokuserer ReactJS primært på at rendere komponenterne i visningslaget. Dette gør det muligt at opbygge komplekse funktioner og samtidig opnå fleksibilitet og genanvendelighed.

Denne artikel vil udforske Reacts funktioner, forklare hvordan det fungerer, og gennemgå dets fordele for front-end-udviklere. ReactJS sammenlignes med React Native og deres roller i web- og mobilapp-udviklingsindustrien diskuteres.

React udvikler
React udvikler
React udvikler
React udvikler
React udvikler

Indholdsfortegnelse

1. Introduktion til React

1.1 Hvad er React?

React er et deklarativt, effektivt og fleksibelt JavaScript-bibliotek til opbygning af brugergrænseflader. Det blev oprindeligt udviklet af Facebook og er nu open source. React er særligt godt til at bygge store webapplikationer, hvor data ændrer sig over tid uden at siden skal genindlæses. React's kernefunktionalitet fokuserer på opbygning af komponenter, som er selvstændige og genbrugelige dele af brugergrænsefladen.

1.2 Hvorfor vælge React?

React er populært blandt udviklere af flere grunde:

  • Deklarativ natur: React gør det enkelt at skabe interaktive brugergrænseflader. Design simple visninger for hver tilstand i din applikation, og React vil effektivt opdatere og renderere de rette komponenter, når dine data ændres.

  • Komponentbaseret: Byg kapslede komponenter, der administrerer deres egen tilstand, og sammensæt dem til komplekse brugergrænseflader.

  • Lær én gang, skriv hvor som helst: Udvikl nye features i React uden at omskrive eksisterende kode. React kan også renderere på serveren ved hjælp af Node og drive mobile apps ved hjælp af React Native.

1.3 Reacts økosystem

Ud over selve biblioteket er der skabt et rigt økosystem omkring React, som inkluderer værktøjer som Redux til tilstandsadministration, React Router til navigation, og mange andre biblioteker, der udvider Reacts funktionalitet. Dette økosystem giver udviklere en robust værktøjskasse til at bygge moderne og skalérbare webapplikationer.

React fortsætter med at være en central del af moderne webudvikling, takket være dets effektive tilgang til opdatering af brugergrænseflader og dets omfattende samfund af bidragydere og udviklere.

2. Grundlæggende

2.1 JSX

JSX er en syntaksudvidelse til JavaScript, som ligner HTML. Det bruges med React for at beskrive, hvordan brugergrænsefladen skal se ud. Ved hjælp af JSX kan udviklere skrive HTML-strukturer i JavaScript-kode, hvilket gør koden mere læsbar og lettere at skrive.

const element = <h1>Hello, world!</h1>;

Dette kodeeksempel viser en enkel JSX, der beskriver et HTML-element.

2.2 Rendering af elementer

Elementer er de mindste byggesten i React-applikationer. Et element beskriver, hvad der skal vises på skærmen. React-elementer er uforanderlige objekter, og når elementets data ændres, skal elementet oprettes på ny.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);

Her oprettes en React rod, og elementet element renderes i en DOM-node med id 'root'.

2.3 Komponenter og props

Komponenter i React kan sammenlignes med JavaScript-funktioner. De accepterer vilkårlige inputs (kaldet "props") og returnerer React-elementer, der beskriver, hvad der skal vises på skærmen.

  • Funktionel komponent:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

Dette er et eksempel på en funktionel komponent, der tager props som input og returnerer et JSX-element.

2.4 State og livscyklus

State giver React-komponenter mulighed for at reagere på brugerinput, serveranmodninger og andre handlinger. Stateful komponenter håndterer state internt og opdaterer brugergrænsefladen i respons til stateændringer.

  • Klassebaseret komponent med state:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>It is {this.state.date.toLocaleTimeString()}.</h1>
      </div>
    );
  }
}

I dette eksempel opretter Clock-klassen en timer, der opdaterer komponentens state hvert sekund, hvilket viser den aktuelle tid.

Disse grundlæggende koncepter danner fundamentet for at bygge dynamiske og interaktive brugergrænseflader med React.

3. Komponenter i React

3.1 Typer af komponenter

I React er der to hovedtyper af komponenter: klassekomponenter og funktionelle komponenter. Begge typer kan bruges til at bygge genanvendelige UI-enheder, men de håndterer logik og tilstand på forskellige måder.

  • Klassekomponenter: Disse komponenter er mere traditionelle i React og defineres som ES6-klasser. De har adgang til livscyklusmetoder og kan holde på tilstand.

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
  • Funktionelle komponenter: Funktionelle komponenter er simplere og defineres som JavaScript-funktioner. De modtager props som argumenter og returnerer React-elementer. Med introduktionen af Hooks, kan funktionelle komponenter også håndtere tilstand og livscyklusfunktioner.

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

3.2 Props vs. State

Props (properties) og state er begge vigtige koncepter i React, men de tjener forskellige formål:

  • Props: Props er en måde at overføre data og begivenheder til en komponent fra dens forælder. Props er skrivebeskyttede, hvilket betyder, at en komponent kun kan læse værdierne af sine props, men ikke ændre dem.

  • State: State er en lokal dataopbevaring, der er tilgængelig kun inden for komponenten selv. Den kan ændres, hvilket kan udløse en genrendering af komponenten. State bruges til data, der skal ændres over tid, som f.eks. brugerinput eller timer værdier.

3.3 Komposition af komponenter

Komponenter kan indlejres i hinanden for at bygge komplekse brugergrænseflader. Dette kaldes komposition, og det er en af de stærke sider ved React.

function App() {
  return (
    <div>
      <Welcome name="Alice" />
      <Welcome name="Bob" />
      <Welcome name="Charlie" />
    </div>
  );
}

I dette eksempel bruger App-komponenten Welcome-komponenten flere gange med forskellige props.

3.4 Nøgler og lister

Når man opretter lister af elementer i React, er det vigtigt at tildele en unik "key"-prop til hvert element i listen. Dette hjælper React med at identificere hvilke elementer der er ændret, tilføjet, eller fjernet, hvilket optimerer genrenderingsprocessen.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

Her bruger NumberList-komponenten en unik nøgle for hvert element for at optimere opdateringer og genrenderinger.

Komponenter er hjørnestenen i React-applikationer, og forståelsen af, hvordan man bruger dem effektivt, er afgørende for at bygge dynamiske og vedligeholdelsesvenlige brugergrænseflader.

4. State og lifecycle

4.1 State

State i React er en privat datastruktur, der opbevares af komponenter og bruges til at styre dynamisk data, der ændrer sig over tid. Ændringer i state for en komponent medfører automatisk en genrendering af komponenten for at afspejle de nye data.

  • Eksempel på state i en klassekomponent:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

I dette eksempel har Counter-komponenten en tilstand, der tæller antallet af klik på en knap.

4.2 Lifecycle-metoder

React-komponenter gennemgår flere "livscyklus"-faser: montering, opdatering og afmontering. React giver lifecycle-metoder, som giver dig mulighed for at udføre handlinger på specifikke tidspunkter i en komponents livscyklus.

  • Montering (Mounting): Når en komponent bliver skabt og indsættes i DOM'en. De vigtigste monteringsmetoder er constructor(), componentDidMount(), og render().

  • Opdatering (Updating): Når en komponent modtager nye props eller state, og React beslutter, at det er nødvendigt at genrende. De primære opdateringsmetoder er shouldComponentUpdate(), componentDidUpdate(), og render().

  • Afmontering (Unmounting): Når en komponent fjernes fra DOM. Metoden componentWillUnmount() kaldes lige før dette sker.

Her er et eksempel, der illustrerer, hvordan man bruger componentDidMount() og componentWillUnmount() til at håndtere eksterne ressourcer:

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { time: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      time: new Date()
    });
  }

  render() {
    return (
      <div>
        <h2>It is {this.state.time.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

I dette eksempel opretter Timer-komponenten en timer, når den monteres, og fjerner timeren, når den afmonteres, for at undgå læk af ressourcer.

Forståelsen af state og lifecycle i React er central for at kunne bygge interaktive og pålidelige applikationer, der opfører sig korrekt gennem hele deres livscyklus.

5. Håndtering af events

5.1 Grundlæggende om event handling

React giver en syntaks, der ligner håndtering af events i almindelig HTML, men med nogle syntaktiske forskelle. React events er navngivet ved hjælp af camelCase snarere end med små bogstaver, som i almindelig HTML. Desuden overføres event-handlere som funktioner snarere end som strenge.

class ToggleButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggledOn: true };
  }

  handleClick = () => {
    this.setState(state => ({
      isToggledOn: !state.isToggledOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggledOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

I dette eksempel skifter knappen status mellem "ON" og "OFF" hver gang den klikkes.

5.2 Binding af this i event handlers

I JavaScript klasser er metoder ikke bundet implicit til klassens instans. Dette betyder, at this i event handlers ikke automatisk vil pege på komponentinstansen, medmindre du binder det manuelt. Der er flere måder at binde this på i React:

  • Bind i constructor: Dette er en almindelig metode, hvor du binder this i konstruktøren.

constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}
  • Class field syntax (offentlig klassefelter syntax): En mere moderne tilgang, der undgår brugen af .bind() ved at bruge class field syntax til at definere metoder som arrow funktioner.

handleClick = () => {
  this.setState(state => ({
    isToggledOn: !state.isToggledOn
  }));
}

5.3 Passing arguments to event handlers

Nogle gange skal du overføre et argument til en event handler. Dette kan gøres ved at bruge en arrow funktion direkte i onClick-attributten eller ved at bruge en funktion, der returnerer en event handler.

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

I dette eksempel overføres id og event-objektet e til deleteRow-metoden, når knappen klikkes.

Håndtering af events er afgørende for at interagere med brugerinput og kontrollere applikationsflowet i React. Korrekt brug af event handling sikrer, at dine React-komponenter reagerer hensigtsmæssigt på brugeraktioner.

6. Conditional rendering

I React kan du skabe forskellige dele af din brugergrænseflade under forskellige betingelser. Det betyder, at du kan vælge at vise eller skjule elementer baseret på bestemte betingelser eller states i din applikation. Conditional rendering i React fungerer på samme måde som betingelser i almindelig JavaScript.

6.1 Anvendelse

Du kan bruge JavaScript-operatører som if eller den conditionelle (ternære) operatør direkte i dine JSX-udtryk for at håndtere visningen af elementer baseret på en betingelse.

  • Brug af if-else til conditional rendering: En almindelig tilgang er at bruge simple if-else statements til at afgøre, hvilke komponenter der skal returneres fra en komponentfunktion.

function WelcomeMessage(props) {
  if (props.isLoggedIn) {
    return <h1>Welcome back!</h1>;
  } else {
    return <h1>Please sign up.</h1>;
  }
}

Her vises en velkomstbesked, hvis brugeren er logget ind, og en opfordring til at tilmelde sig, hvis de ikke er det.

  • Brug af ternære operatører: Ternære operatører er især nyttige for inline conditional rendering i JSX.

function WelcomeMessage(props) {
  return (
    <div>
      {props.isLoggedIn ? (
        <h1>Welcome back!</h1>
      ) : (
        <h1>Please sign up.</h1>
      )}
    </div>
  );
}

Dette eksempel opnår det samme som det forrige, men det gøres direkte inden i JSX'en, hvilket kan være mere læsbart for mindre og mere direkte betingelser.

6.2 Skjul komponenter ved at returnere null

En vigtig ting at bemærke om conditional rendering i React er, at du kan forhindre en komponent i at blive renderet ved at returnere null fra en komponents render-metode.

  • Eksempel på at returnere null:

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

I dette eksempel vil WarningBanner kun blive renderet, hvis props.warn er sandt. Hvis det er falsk, renderes intet, hvilket effektivt skjuler komponenten.

Conditional rendering er en kraftfuld teknik i React, der gør det muligt at bygge dynamiske og responsive applikationer. Ved at integrere simpel JavaScript-logik direkte i dine komponenter, kan du nemt kontrollere, hvilke dele af din applikation der er synlige for brugeren under forskellige forhold.

7. Lister og keys

7.1 Rendere lister

At arbejde med lister er en almindelig opgave i webudvikling. I React kan lister af elementer blive rendret ved at bruge JavaScripts map() funktion til at transformere et array af data til et array af JSX-elementer.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

I dette eksempel omdannes hvert tal i arrayet numbers til et <li>-element. Nøglen til effektivt at rendere lister er brugen af key-props, som vil blive uddybet nærmere.

7.2 Brug af keys

Keys hjælper React med at identificere hvilke elementer der er ændret, tilføjet eller fjernet, hvilket kan forbedre ydeevnen ved dynamisk opdatering af lister. Keys bør gives til elementerne inde i arrayet for at give en stabil identitet.

  • Vælg passende keys: Nøglerne bør være unikke blandt søskendeelementerne i listen. Typisk vil du bruge IDs fra dine data som keys. Hvis du ikke har stabile IDs for rendrede elementer, kan du bruge elementets indeks som en sidste udvej, selvom det ikke anbefales, da det kan påvirke ydeevnen og forårsage problemer med komponentens tilstand.

const todoItems = todos.map((todo, index) =>
  // Kun brug indeks som nøgle, hvis elementerne ikke har stabile IDs
  <li key={index}>
    {todo.text}
  </li>
);

7.3 Problemer med indeks som key

Brug af indekser som keys er ikke ideelt, hvis listen kan ændres. Hvis listen reordnes eller elementer indsættes i begyndelsen, vil indekserne ændres, hvilket kan føre til yderligere genrenderinger og en fejlagtig tilstandsbehandling.

7.4 Nøgler og komponenttilstand

Når du bruger keys, er det vigtigt at forstå, at de kun er relevante inden for konteksten af den nærmeste map()-kald. De har ingen betydning for, hvordan komponenter behandler deres tilstand, da React håndterer hver komponent separat baseret på dens nøgle.

Ved at bruge keys korrekt, sikrer du, at Reacts genrenderingsproces er så effektiv som muligt, og at din applikations ydeevne optimeres, når du arbejder med lister.

8. Formularer

Formularer i React kan håndteres på en måde, der ligner håndtering af almindelige DOM-formularer, men med en vigtig React-specifik tilføjelse: kontrollerede komponenter. Ved at gøre en React-komponent til "kontrolleret", styrer du dens værdier via state og reagerer på ændringer via event handlers.

8.1 Kontrollerede komponenter

I kontrollerede komponenter er formulardata håndteret af React-komponentens tilstand. Du skriver en event handler for at opdatere tilstanden, hver gang en bruger skriver noget ind i en formular.

  • Eksempel på en kontrolleret input:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

I dette eksempel kontrolleres input-komponenten helt af React, hvilket gør data flowet mere forudsigeligt og lettere at debugge.

8.2 Ikke-kontrollerede komponenter

I modsætning til kontrollerede komponenter anvender ikke-kontrollerede komponenter ref'er til at hente værdier fra DOM-elementerne, når du har brug for dem, snarere end at gemme hver ændring i tilstanden.

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.input = React.createRef();
  }

  handleSubmit = (event) => {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Dette eksempel viser en formular, hvor input-værdien tilgås gennem en ref ved formularindsendelse, i stedet for at hver ændring opdaterer komponentens tilstand.

8.3 Håndtering af flere inputs

Når du håndterer flere kontrollerede input-elementer, kan du tilføje en name-attribut til hver input og lade handleren vælge, hvad der skal gøres baseret på event.target.name.

handleChange(event) {
  const target = event.target;
  const value = target.type === 'checkbox' ? target.checked : target.value;
  const name = target.name;

  this.setState({
    [name]: value
  });
}

Denne teknik gør det nemt at håndtere flere forskellige inputs med en enkelt funktion, hvilket reducerer mængden af kode, der er nødvendig for at håndtere komplekse formularer.

Formularhåndtering er en essentiel del af mange webapplikationer, og ved at forstå forskellen mellem kontrollerede og ikke-kontrollerede komponenter, kan du vælge den tilgang, der bedst passer til dit projekt.

9. Avancerede React-teknikker

9.1 Lifting state up

Når flere komponenter har brug for at dele og manipulere de samme data, anbefales det at "løfte staten op" til deres nærmeste fælles forælder. Dette betyder, at du skal opbevare den delte tilstand i forælderkomponenten i stedet for at prøve at synkronisere staten mellem forskellige børnekomponenter.

class TemperatureCalculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {temperature: ''};

    this.handleTemperatureChange = this.handleTemperatureChange.bind(this);
  }

  handleTemperatureChange(temperature) {
    this.setState({temperature});
  }

  render() {
    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={this.state.temperature}
          onTemperatureChange={this.handleTemperatureChange} />
        <TemperatureInput
          scale="f"
          temperature={this.state.temperature}
          onTemperatureChange={this.handleTemperatureChange} />
      </div>
    );
  }
}

I dette eksempel håndterer TemperatureCalculator komponenten tilstanden for temperatur og passer den ned til TemperatureInput børnekomponenter.

9.2 Sammensætning vs. inheritance

I React foretrækkes sammensætning over inheritance for at genbruge kode mellem komponenter. Brug af sammensætning kan involvere børnekomponenter, render props, eller højere ordens komponenter til at bygge mere komplekse UI'er fra enkle byggesten.

  • Eksempel på brug af sammensætning:

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
      {props.children}
    </FancyBorder>
  );
}

Her bruger Dialog komponenten FancyBorder komponenten som en container, hvilket demonstrerer sammensætning.

9.3 Hooks

Hooks er en funktion i React 16.8, som lader dig bruge state og andre React-funktioner uden at skrive en klasse. De mest almindelige hooks er useState og useEffect.

  • Eksempel på brug af useState og useEffect:

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Her håndterer Example komponenten en tæller ved hjælp af useState og opdaterer dokumentets titel ved hjælp af useEffect.

9.4 Context

Context giver en måde at dele værdier som f.eks. brugerautentificering, temaer, eller sprogpræferencer på tværs af mange komponenter uden at sende props manuelt på alle niveauer af træet.

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme}>I am styled by theme context!</button>}
    </ThemeContext.Consumer>
  );
}

I dette eksempel passer App en "dark" tema værdi ned gennem Toolbar til ThemedButton ved hjælp af Context, uden at manuelt proppe den ned gennem hver komponent.

Disse avancerede teknikker giver dig mulighed for at bygge mere effektive og vedligeholdelsesvenlige React-applikationer, idet de udnytter kraftfulde mønstre og funktioner i React-biblioteket.

9.5 Error boundaries

Error boundaries er en nyttig funktion i React, der tillader en komponent at fange JavaScript-fejl hvor som helst i dens underkomponenters træ. Dette forhindrer hele appen i at crashe og giver dig mulighed for at vise en fallback UI, når der sker en fejl.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Opdater tilstanden, så den næste render viser fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // Du kan også logge fejlen til en fejlrapporteringstjeneste
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // Du kan render et hvilket som helst custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

Brug ErrorBoundary som en wrapper omkring enhver komponent, hvor du ønsker at håndtere fejl. Hvis en fejl opstår i en af underkomponenterne, vil ErrorBoundary fange den og vise et fallback UI.

9.6 Refs og DOM

Refs giver adgang til DOM-noder direkte i React-komponenter. Dette er nyttigt for en række opgaver, som fokusering på et inputfelt, afspilning af medieindhold eller udløsning af animaer.

  • Eksempel på brug af refs:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  focusTextInput = () => {
    // Eksplicit fokusere på tekst input ved hjælp af den rå DOM API
    this.textInput.current.focus();
  }

  render() {
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <button
          onClick={this.focusTextInput}>
          Focus the text input
        </button>
      </div>
    );
  }
}

I dette eksempel bruger CustomTextInput en ref til at opbevare en reference til input-elementet og fokuserer det, når en knap klikkes.

9.7 Optimering af ydeevne

React-apps kan skaleres effektivt, men nogle gange kan komplekse applikationer lide af langsomme renderinger eller forsinkelser. Brug af teknikker som React.memo, useCallback, useMemo og korrekt brug af keys kan hjælpe med at reducere antallet af unødvendige genrenderinger og dermed forbedre ydeevnen.

  • Eksempel på brug af React.memo:

const MyComponent = React.memo(function MyComponent(props) {
  /* render ved hjælp af props */
});

React.memo er en higher order component, som kun tillader komponenten at opdatere, hvis dens props har ændret sig, hvilket er nyttigt for at undgå dyre genrenderinger i komponenter, der modtager de samme props med identiske værdier over gentagne renders.

Disse avancerede teknikker i React giver dig værktøjer til at skrive mere robuste, vedligeholdelsesvenlige og performante webapplikationer. Ved at mestre disse metoder kan du udnytte Reacts fulde potentiale og bygge apps, der er både hurtige og pålidelige.

9.8 Context API for dybere statshåndtering

React's Context API tillader en effektiv måde at dele værdier som globale data (f.eks., tema, brugerpræferencer, autentificering) på tværs af en komponenttræ uden at skulle manuelt sende props på hvert niveau. Dette er særligt nyttigt for dybt nestede komponenter.

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme}>I am styled by theme context!</button>}
    </ThemeContext.Consumer>
  );
}

I dette eksempel defineres en ThemeContext med en standardværdi 'light'. App-komponenten bruger derefter ThemeContext.Provider til at angive temaet til 'dark', som så anvendes i ThemedButton via ThemeContext.Consumer.

9.9 Brug af Higher Order Components (HOCs)

Higher Order Components er en avanceret teknik i React for genbrug af komponentlogik. En HOC er en funktion, der tager en komponent og returnerer en ny komponent. De bruges ofte til at tilføje ekstra funktionalitet til eksisterende komponenter.

function withSubscription(WrappedComponent, selectData) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ... Tilføjer event listeners eller andet setup
    }

    componentWillUnmount() {
      // ... Fjerner event listeners eller andet cleanup
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

Denne HOC withSubscription kunne bruges til at håndtere abonnering på datakilder og videregive data til en komponent som en prop.

9.10 Brug af Hooks for sideeffekter

Hooks tillader funktionelle komponenter at håndtere sideeffekter, interne statshåndtering og mere. useEffect er en Hook, der gør det muligt at udføre sideeffekter i funktionelle komponenter. Det kan bruges til at håndtere abonnementer, timere, API-kald, og mere.

  • Eksempel på brug af useEffect:

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Du klikkede ${count} gange`;

    return () => {
      document.title = 'React App';
    };
  }, [count]);  // Kun genkør effekten hvis count ændres

  return (
    <div>
      <p>Du klikkede {count} gange</p>
      <button onClick={() => setCount(count + 1)}>
        Klik mig
      </button>
    </div>
  );
}

Her opdaterer useEffect dokumentets titel, når count ændres, og nulstiller den, når komponenten fjernes.

Disse avancerede teknikker styrker React's fleksibilitet og udtryksfuldhed, og giver udviklere kraftfulde værktøjer til at bygge komplekse og højt optimerede applikationer.

10. React Router

React Router er et standardbibliotek i React-økosystemet, der anvendes til at håndtere navigation og routing i React-applikationer. Det giver mulighed for at opbygge en single-page application (SPA) med navigation, der ligner multi-page websites, hvor URL-adressen ændres uden at siden genindlæses.

React Router tilbyder flere komponenter som <BrowserRouter>, <Route>, <Link>, <Switch>, og <Redirect> til at håndtere routing. Disse komponenter giver dig mulighed for at definere navigationsstrukturer, link til forskellige dele af din applikation, og vælge visningen baseret på URL'en.

  • Opsætning af React Router:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

I dette eksempel bruges <Switch> til at eksklusivt vælge en <Route> baseret på URL'en. <Route> komponenterne definerer hvilken komponent, der skal renderes, baseret på den aktuelle sti.

10.1 Navigation og Links

For at oprette links i din applikation uden at genindlæse siden, bruger React Router <Link> komponenten, som forhindrer standard browseropførsel og opdaterer browserens URL-bar.

  • Eksempel på brug af Link:

import { Link } from 'react-router-dom';

function Navbar() {
  return (
    <nav>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/about">About</Link>
        </li>
        <li>
          <Link to="/users">Users</Link>
        </li>
      </ul>
    </nav>
  );
}

Her skaber <Link> komponenter navigerbare links, der ikke genindlæser siden, men opdaterer visningen baseret på den valgte rute.

10.2 Dynamisk routing

React Router understøtter også dynamisk routing, hvor parametre kan indgå i URL-stien og derefter tilgås i din komponent.

<Route path="/user/:id" component={User} />

I dette eksempel vil en URL som /user/123 matche ovenstående rute, hvor 123 vil være tilgængelig som en parameter i User-komponenten.

10.3 Programmér navigation

Ud over at bruge <Link> til at ændre ruter, kan du programmært navigere med React Router ved hjælp af historieobjektet, som du kan få adgang til gennem useHistory hook.

import { useHistory } from 'react-router-dom';

function HomeButton() {
  let history = useHistory();

  function handleClick() {
    history.push('/home');
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

I dette eksempel navigerer knappen brugeren til /home stien, når den klikkes, ved at tilføje den nye lokation til browserens historikstak.

React Router er et kraftfuldt værktøj, der gør det muligt for React-udviklere at bygge komplekse navigationsstrukturer og forbedre brugeroplevelsen i single-page applikationer.

11. Redux

Redux er en populær bibliotek til tilstandsstyring for JavaScript-applikationer, ofte anvendt sammen med React, men det kan bruges med ethvert andet JavaScript-framework eller bibliotek. Det er især nyttigt for store applikationer med komplekse datastrømme og mange interaktioner, hvor flere komponenter kræver adgang til den samme applikationstilstand.

Redux centraliserer applikationens tilstand i et enkelt "store", hvilket gør det lettere at holde styr på tilstandsændringer over tid. I Redux er al tilstandsændring logik skrevet i form af "reducers" – funktioner, der tager den forrige tilstand og en "action" og returnerer en ny tilstand.

  • Eksempel på en Redux reducer:

function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

I dette eksempel håndterer counter reduceren to aktionstyper: INCREMENT og DECREMENT. Reduceren opdaterer tilstanden baseret på hvilken handling der er udført.

11.1 Actions og Action Creators

Actions i Redux er JavaScript-objekter, der beskriver ændringer i applikationen. De skal have en type-egenskab, der angiver typen af handling, der skal udføres. Action creators er funktioner, der returnerer en action.

  • Eksempel på en action og en action creator:

function increment() {
  return { type: 'INCREMENT' };
}

function decrement() {
  return { type: 'DECREMENT' };
}

Disse funktioner, increment og decrement, er action creators, der skaber og returnerer actions, som kan dispatches til store.

11.2 Anvendelse af Redux

For at integrere Redux med React anvendes react-redux biblioteket, som tilbyder Provider og connect funktioner til at binde Redux store med React-komponenter.

  • Opsætning af Redux med React:

import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
import App from './App';

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Provider-komponenten omslutter hele applikationen og gør Redux store tilgængelig for alle nestede komponenter.

11.3 Middleware og asynkrone aktioner

Redux understøtter middleware, som giver mulighed for at udvide Redux med brugerdefineret funktionalitet, for eksempel for at håndtere asynkrone operationer. Det mest populære middleware til Redux er Redux Thunk, som gør det muligt at skrive action creators, der returnerer en funktion i stedet for en action.

  • Eksempel på anvendelse af Redux Thunk:

function fetchData() {
  return (dispatch) => {
    fetch('<https://api.example.com/data>')
      .then(response => response.json())
      .then(data => dispatch({ type: 'RECEIVE_DATA', data }));
  };
}

I dette eksempel henter fetchData asynkront data og dispatches en action, når data er modtaget.

Redux tilbyder en robust løsning til håndtering af applikationstilstande, hvilket gør det nemmere at udvikle vedligeholdelige og forudsigelige webapplikationer ved at følge strenge regler for hvordan tilstanden opdateres og overføres gennem applikationen.

13. React og TypeScript

13.1 Integrering af TypeScript i React

TypeScript er et populært, typet overbygning til JavaScript, der tilføjer statiske typer og avancerede objektorienterede funktioner. Når det anvendes sammen med React, forbedrer TypeScript pålideligheden og vedligeholdelsen af kode ved at tilføje typekontroller, hvilket gør det lettere at udvikle store eller komplekse applikationer.

13.2 Opsætning af et React-projekt med TypeScript

Oprettelse af et nyt React-projekt med TypeScript kan nemt gøres ved hjælp af Create React App, som understøtter TypeScript ud af boksen.

  • Start et nyt React + TypeScript projekt:

npx create-react-app my-app --template typescript

Dette kommando initierer et nyt projekt, inkluderer TypeScript konfigurationen, og opsætter alt nødvendigt for at begynde at arbejde med React og TypeScript.

13.3 Definere komponenter med TypeScript

Når du definerer React-komponenter med TypeScript, kan du specificere typer for props og state, hvilket giver en robust typekontrol gennem hele komponentens livscyklus.

  • Eksempel på en funktionel komponent med props:

type AppProps = {
  title: string;
  isActive: boolean;
};

const App: React.FC<AppProps> = ({ title, isActive }) => {
  return <div>{isActive ? title : "Inactive"}</div>

Dette eksempel viser en funktionel komponent, hvor propstyperne er defineret klart, hvilket hjælper TypeScript med at verificere korrekt brug af komponenten i applikationen.

13.4 Brug af Hooks med TypeScript

TypeScript forbedrer brugen af React Hooks ved at tillade typer at blive angivet for hooks som useState og useEffect, hvilket giver yderligere sikkerhed i håndteringen af applikationstilstand.

  • Eksempel på useState med TypeScript:

const [isOnline, setIsOnline] = useState<boolean>(false);

Her angiver useState-typen boolean, hvilket sikrer, at isOnline og setIsOnline håndterer boolean værdier korrekt.

13.5 Fordele ved at bruge TypeScript med React

Brug af TypeScript i React-projekter tilbyder flere fordele:

  • Forbedret kodekvalitet: Stærke typekontroller hjælper med at identificere mange potentielle fejl under udviklingen, før softwaren når produktion.

  • Bedre værktøjsstøtte: Moderne IDE'er og redaktører tilbyder bedre navigation og autokomplet med TypeScript, hvilket forbedrer udviklerens effektivitet.

  • Lettere refaktorering: Sikker refaktorering af kode bliver lettere, da ændringer, der bryder typekontrakter, hurtigt kan identificeres.

13.6 Udfordringer

Selvom TypeScript tilføjer mange fordele, kommer det også med en læringskurve. Udviklere skal være fortrolige med TypeScript's type system, og der kan være en initial opsætnings- og konfigurationsoverhead, især i eksisterende projekter, der overgår til TypeScript.

Integrering af TypeScript i React-applikationer er en investering, der kan øge produktiviteten og sikkerheden i applikationsudviklingen, og gøre det lettere at vedligeholde og skalere applikationer over tid.

14. Best practices

14.1 Kodekvalitet og vedligeholdelse

At opretholde høj kodekvalitet og god kodevedligeholdelse er afgørende for at sikre, at React-applikationer forbliver skalérbare og nemme at administrere. Her er nogle best practices for at opnå dette:

  • Komponentopdeling: Opdel UI i genanvendelige, små komponenter, der hver især håndterer en specifik funktion. Dette fremmer genbrug og gør koden lettere at teste og vedligeholde.

  • Klare ansvarsområder: Hver komponent bør have et veldefineret ansvarsområde. Undgå at gøre komponenter for "smarte" eller overbelastede med logik.

  • Prop-types og TypeScript: Brug prop-types eller TypeScript til at definere og validere typer af props, som komponenter modtager. Dette øger robustheden og forudsigeligheden af din kode.

14.2 Statehåndtering

Effektiv håndtering af tilstand er kritisk i React-applikationer:

  • Lift state up: Når flere komponenter deler den samme tilstand, bør du løfte tilstanden op til deres nærmeste fælles forælder. Dette centraliserer tilstanden og letter kommunikationen mellem komponenter.

  • Brug Redux omhyggeligt: Overvej Redux eller en anden tilstandshåndteringsbibliotek, når applikationen bliver for stor eller kompleks til enkel prop-drilling eller React Context er utilstrækkelig.

14.3 Ydeevneoptimering

Ydeevne er en anden kritisk faktor, især i større applikationer:

  • Memoization: Brug React.memo, useMemo, og useCallback for at forhindre unødvendige genrenderinger ved at huske tidligere output baseret på de samme inputs.

  • Lazy loading: Brug React.lazy for dynamisk import af komponenter, der ikke er nødvendige ved den første load, hvilket kan reducere starttidspunktet.

14.4 Accessibility (Tilgængelighed)

Tilgængelighed bør være en integreret del af design og udvikling:

  • Semantiske HTML-elementer: Brug passende HTML5-elementer, som hjælper med at guide skærmlæsere og andre assistive teknologier.

  • ARIA-attributter: Brug ARIA-roller og attributter, når semantiske HTML-elementer ikke er tilstrækkelige.

14.5 Testing

Sikre, at applikationen er stabil og fejlfri gennem omfattende testning:

  • Enhedstest: Test individuelle komponenter for at sikre, at de fungerer som forventet uafhængigt.

  • Integrationstest: Test integrationen mellem flere komponenter og deres samspil med tilstandshåndtering.

  • E2E-test: Simuler brugerens end-to-end arbejdsflow for at sikre, at hele applikationen fungerer som forventet.

14.6 Udviklerværktøjer

Benyt avancerede værktøjer og udvidelser som React Developer Tools til at inspicere og debugge React-komponenter. Disse værktøjer kan give indsigt i komponenttræer, tilstandsændringer og ydeevneproblemer.

Ved at følge disse best practices kan udviklere opbygge robuste, effektive og vedligeholdelsesvenlige React-applikationer, der er klar til produktion og skalerbare til fremtidens krav.

15. Ressourcer og samfund

15.1 Læringsressourcer

React-økosystemet er støttet af et omfattende udvalg af læringsmaterialer og dokumentation, der kan hjælpe udviklere på alle niveauer med at forbedre deres færdigheder og forståelse af biblioteket.

  • Officiel dokumentation: Reacts officielle dokumentation (reactjs.org) er en omfattende ressource, der dækker alle aspekter af biblioteket, fra grundlæggende begreber til avancerede teknikker.

  • Online kurser: Platforme som Udemy, Coursera, og freeCodeCamp tilbyder kurser i React, der spænder fra begynder til avancerede niveauer.

  • Video-tutorials: YouTube-kanaler og andre videoplatforme tilbyder gratis ressourcer, der demonstrerer specifikke teknikker og bedste praksisser.

15.2 Community support

React har et levende og støttende samfund, som er en uvurderlig ressource for både nye og erfarne udviklere.

  • Stack Overflow: En platform, hvor man kan stille spørgsmål og få svar fra andre udviklere.

  • GitHub: Reacts kildekode og mange tredjepartsbiblioteker er tilgængelige på GitHub, hvor udviklere kan bidrage til open source-projekter og følge udviklingen.

  • Reddit og sociale medier: Fora som Reddit, Twitter, og LinkedIn grupper tilbyder steder at dele viden, diskutere problemer, og netværke med andre React-udviklere.

15.3 Konferencer og Meetups

Deltagelse i konferencer og lokale meetups kan give værdifulde læringsmuligheder og chancen for at møde andre i industrien.

  • React konferencer: Arrangementer som React Conf og ReactEurope samler ledende eksperter og entusiaster for at dele deres viden og erfaringer.

  • Meetup-grupper: Lokale meetup-grupper tilbyder regelmæssige møder, workshops og hackathons, hvor man kan lære af og samarbejde med andre udviklere.

15.4 Open Sourceprojekter

Bidrag til open source-projekter er en fremragende måde at lære React på, forbedre dine udviklingsevner og give tilbage til fællesskabet.

  • Bidrage til React: Udviklere opfordres til at bidrage til React selv, hvad enten det handler om at forbedre dokumentationen eller at løse issues.

  • Tredjepartsbiblioteker: Der findes et utal af React-relaterede biblioteker og projekter, der søger bidrag fra fællesskabet.

15.5 Kontinuerlig læring

Teknologier udvikler sig konstant, og det samme gælder for React-økosystemet. Det er vigtigt for udviklere at holde sig opdateret med de nyeste ændringer, features og bedste praksisser.

  • Abonner på blogs og nyhedsbreve: Følg eksperter og læs regelmæssigt blogs og nyhedsbreve for at holde sig ajour med de seneste trends og opdateringer.

  • Deltag i kodningsudfordringer: Online platforms som CodeSignal og LeetCode tilbyder kodningsproblemer, der kan hjælpe med at skærpe dine færdigheder og lære nye tilgange.

Ved at udnytte disse ressourcer og engagere sig i React-samfundet, kan udviklere bygge stærke netværk, avancere deres karrierer og forblive på forkant med moderne webudvikling.

16. Konklusion

React er et utroligt kraftfuldt og alsidigt JavaScript-bibliotek, der har revolutioneret måden, vi tænker på at bygge brugergrænseflader på. Fra små startprojekter til store skala enterprise-applikationer, Reacts komponentbaserede arkitektur tilbyder en effektiv, deklarativ og fleksibel tilgang til udvikling af webapplikationer.

Med et robust økosystem, der omfatter værktøjer som Redux for tilstandsstyring, React Router for navigation, og et væld af tredjeparts biblioteker, har udviklere adgang til alt det nødvendige for at bygge dynamiske og interaktive applikationer. Integrationen af TypeScript tilføjer yderligere styrker til type-sikkerhed, hvilket gør React endnu mere robust og vedligeholdelsesvenlig.

Det aktive og støttende React-samfund spiller en afgørende rolle i bibliotekets vedvarende popularitet og udvikling. Ved at deltage i dette samfund, uanset om det er gennem online fora, lokale meetups eller store konferencer, kan udviklere dele viden, løse problemer og finde nye muligheder for samarbejde.

Udnyttelsen af de bedste praksisser og fortsat uddannelse i nye funktioner og mønstre er nøglen til at mestre React. Ved at holde sig ajour med de seneste trends og teknologier, kan React-udviklere sikre, at deres færdigheder forbliver relevante og efterspurgte i den hurtigt udviklende verden af webudvikling.

Konklusionen er, at React ikke kun er et bibliotek til at bygge applikationer; det er en gateway til at bygge moderne, effektive og skalerbare løsninger, der kan tilpasse sig fremtidige teknologiske fremskridt og brugerkrav. For nye og erfarne udviklere, der ønsker at være i forkant med moderne webteknologier, er React et uundværligt redskab i udviklingsarsenalet.

Har du brug for en React udvikler til dit næste IT-projekt? Hos Better Developers hjælper vi dig med at finde den rette udvikler til lige netop dine behov. Læs om React konsulenter hos Better Developers her.

1. Introduktion til React

1.1 Hvad er React?

React er et deklarativt, effektivt og fleksibelt JavaScript-bibliotek til opbygning af brugergrænseflader. Det blev oprindeligt udviklet af Facebook og er nu open source. React er særligt godt til at bygge store webapplikationer, hvor data ændrer sig over tid uden at siden skal genindlæses. React's kernefunktionalitet fokuserer på opbygning af komponenter, som er selvstændige og genbrugelige dele af brugergrænsefladen.

1.2 Hvorfor vælge React?

React er populært blandt udviklere af flere grunde:

  • Deklarativ natur: React gør det enkelt at skabe interaktive brugergrænseflader. Design simple visninger for hver tilstand i din applikation, og React vil effektivt opdatere og renderere de rette komponenter, når dine data ændres.

  • Komponentbaseret: Byg kapslede komponenter, der administrerer deres egen tilstand, og sammensæt dem til komplekse brugergrænseflader.

  • Lær én gang, skriv hvor som helst: Udvikl nye features i React uden at omskrive eksisterende kode. React kan også renderere på serveren ved hjælp af Node og drive mobile apps ved hjælp af React Native.

1.3 Reacts økosystem

Ud over selve biblioteket er der skabt et rigt økosystem omkring React, som inkluderer værktøjer som Redux til tilstandsadministration, React Router til navigation, og mange andre biblioteker, der udvider Reacts funktionalitet. Dette økosystem giver udviklere en robust værktøjskasse til at bygge moderne og skalérbare webapplikationer.

React fortsætter med at være en central del af moderne webudvikling, takket være dets effektive tilgang til opdatering af brugergrænseflader og dets omfattende samfund af bidragydere og udviklere.

2. Grundlæggende

2.1 JSX

JSX er en syntaksudvidelse til JavaScript, som ligner HTML. Det bruges med React for at beskrive, hvordan brugergrænsefladen skal se ud. Ved hjælp af JSX kan udviklere skrive HTML-strukturer i JavaScript-kode, hvilket gør koden mere læsbar og lettere at skrive.

const element = <h1>Hello, world!</h1>;

Dette kodeeksempel viser en enkel JSX, der beskriver et HTML-element.

2.2 Rendering af elementer

Elementer er de mindste byggesten i React-applikationer. Et element beskriver, hvad der skal vises på skærmen. React-elementer er uforanderlige objekter, og når elementets data ændres, skal elementet oprettes på ny.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(element);

Her oprettes en React rod, og elementet element renderes i en DOM-node med id 'root'.

2.3 Komponenter og props

Komponenter i React kan sammenlignes med JavaScript-funktioner. De accepterer vilkårlige inputs (kaldet "props") og returnerer React-elementer, der beskriver, hvad der skal vises på skærmen.

  • Funktionel komponent:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

Dette er et eksempel på en funktionel komponent, der tager props som input og returnerer et JSX-element.

2.4 State og livscyklus

State giver React-komponenter mulighed for at reagere på brugerinput, serveranmodninger og andre handlinger. Stateful komponenter håndterer state internt og opdaterer brugergrænsefladen i respons til stateændringer.

  • Klassebaseret komponent med state:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>It is {this.state.date.toLocaleTimeString()}.</h1>
      </div>
    );
  }
}

I dette eksempel opretter Clock-klassen en timer, der opdaterer komponentens state hvert sekund, hvilket viser den aktuelle tid.

Disse grundlæggende koncepter danner fundamentet for at bygge dynamiske og interaktive brugergrænseflader med React.

3. Komponenter i React

3.1 Typer af komponenter

I React er der to hovedtyper af komponenter: klassekomponenter og funktionelle komponenter. Begge typer kan bruges til at bygge genanvendelige UI-enheder, men de håndterer logik og tilstand på forskellige måder.

  • Klassekomponenter: Disse komponenter er mere traditionelle i React og defineres som ES6-klasser. De har adgang til livscyklusmetoder og kan holde på tilstand.

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
  • Funktionelle komponenter: Funktionelle komponenter er simplere og defineres som JavaScript-funktioner. De modtager props som argumenter og returnerer React-elementer. Med introduktionen af Hooks, kan funktionelle komponenter også håndtere tilstand og livscyklusfunktioner.

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

3.2 Props vs. State

Props (properties) og state er begge vigtige koncepter i React, men de tjener forskellige formål:

  • Props: Props er en måde at overføre data og begivenheder til en komponent fra dens forælder. Props er skrivebeskyttede, hvilket betyder, at en komponent kun kan læse værdierne af sine props, men ikke ændre dem.

  • State: State er en lokal dataopbevaring, der er tilgængelig kun inden for komponenten selv. Den kan ændres, hvilket kan udløse en genrendering af komponenten. State bruges til data, der skal ændres over tid, som f.eks. brugerinput eller timer værdier.

3.3 Komposition af komponenter

Komponenter kan indlejres i hinanden for at bygge komplekse brugergrænseflader. Dette kaldes komposition, og det er en af de stærke sider ved React.

function App() {
  return (
    <div>
      <Welcome name="Alice" />
      <Welcome name="Bob" />
      <Welcome name="Charlie" />
    </div>
  );
}

I dette eksempel bruger App-komponenten Welcome-komponenten flere gange med forskellige props.

3.4 Nøgler og lister

Når man opretter lister af elementer i React, er det vigtigt at tildele en unik "key"-prop til hvert element i listen. Dette hjælper React med at identificere hvilke elementer der er ændret, tilføjet, eller fjernet, hvilket optimerer genrenderingsprocessen.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

Her bruger NumberList-komponenten en unik nøgle for hvert element for at optimere opdateringer og genrenderinger.

Komponenter er hjørnestenen i React-applikationer, og forståelsen af, hvordan man bruger dem effektivt, er afgørende for at bygge dynamiske og vedligeholdelsesvenlige brugergrænseflader.

4. State og lifecycle

4.1 State

State i React er en privat datastruktur, der opbevares af komponenter og bruges til at styre dynamisk data, der ændrer sig over tid. Ændringer i state for en komponent medfører automatisk en genrendering af komponenten for at afspejle de nye data.

  • Eksempel på state i en klassekomponent:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

I dette eksempel har Counter-komponenten en tilstand, der tæller antallet af klik på en knap.

4.2 Lifecycle-metoder

React-komponenter gennemgår flere "livscyklus"-faser: montering, opdatering og afmontering. React giver lifecycle-metoder, som giver dig mulighed for at udføre handlinger på specifikke tidspunkter i en komponents livscyklus.

  • Montering (Mounting): Når en komponent bliver skabt og indsættes i DOM'en. De vigtigste monteringsmetoder er constructor(), componentDidMount(), og render().

  • Opdatering (Updating): Når en komponent modtager nye props eller state, og React beslutter, at det er nødvendigt at genrende. De primære opdateringsmetoder er shouldComponentUpdate(), componentDidUpdate(), og render().

  • Afmontering (Unmounting): Når en komponent fjernes fra DOM. Metoden componentWillUnmount() kaldes lige før dette sker.

Her er et eksempel, der illustrerer, hvordan man bruger componentDidMount() og componentWillUnmount() til at håndtere eksterne ressourcer:

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { time: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      time: new Date()
    });
  }

  render() {
    return (
      <div>
        <h2>It is {this.state.time.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

I dette eksempel opretter Timer-komponenten en timer, når den monteres, og fjerner timeren, når den afmonteres, for at undgå læk af ressourcer.

Forståelsen af state og lifecycle i React er central for at kunne bygge interaktive og pålidelige applikationer, der opfører sig korrekt gennem hele deres livscyklus.

5. Håndtering af events

5.1 Grundlæggende om event handling

React giver en syntaks, der ligner håndtering af events i almindelig HTML, men med nogle syntaktiske forskelle. React events er navngivet ved hjælp af camelCase snarere end med små bogstaver, som i almindelig HTML. Desuden overføres event-handlere som funktioner snarere end som strenge.

class ToggleButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggledOn: true };
  }

  handleClick = () => {
    this.setState(state => ({
      isToggledOn: !state.isToggledOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggledOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

I dette eksempel skifter knappen status mellem "ON" og "OFF" hver gang den klikkes.

5.2 Binding af this i event handlers

I JavaScript klasser er metoder ikke bundet implicit til klassens instans. Dette betyder, at this i event handlers ikke automatisk vil pege på komponentinstansen, medmindre du binder det manuelt. Der er flere måder at binde this på i React:

  • Bind i constructor: Dette er en almindelig metode, hvor du binder this i konstruktøren.

constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}
  • Class field syntax (offentlig klassefelter syntax): En mere moderne tilgang, der undgår brugen af .bind() ved at bruge class field syntax til at definere metoder som arrow funktioner.

handleClick = () => {
  this.setState(state => ({
    isToggledOn: !state.isToggledOn
  }));
}

5.3 Passing arguments to event handlers

Nogle gange skal du overføre et argument til en event handler. Dette kan gøres ved at bruge en arrow funktion direkte i onClick-attributten eller ved at bruge en funktion, der returnerer en event handler.

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

I dette eksempel overføres id og event-objektet e til deleteRow-metoden, når knappen klikkes.

Håndtering af events er afgørende for at interagere med brugerinput og kontrollere applikationsflowet i React. Korrekt brug af event handling sikrer, at dine React-komponenter reagerer hensigtsmæssigt på brugeraktioner.

6. Conditional rendering

I React kan du skabe forskellige dele af din brugergrænseflade under forskellige betingelser. Det betyder, at du kan vælge at vise eller skjule elementer baseret på bestemte betingelser eller states i din applikation. Conditional rendering i React fungerer på samme måde som betingelser i almindelig JavaScript.

6.1 Anvendelse

Du kan bruge JavaScript-operatører som if eller den conditionelle (ternære) operatør direkte i dine JSX-udtryk for at håndtere visningen af elementer baseret på en betingelse.

  • Brug af if-else til conditional rendering: En almindelig tilgang er at bruge simple if-else statements til at afgøre, hvilke komponenter der skal returneres fra en komponentfunktion.

function WelcomeMessage(props) {
  if (props.isLoggedIn) {
    return <h1>Welcome back!</h1>;
  } else {
    return <h1>Please sign up.</h1>;
  }
}

Her vises en velkomstbesked, hvis brugeren er logget ind, og en opfordring til at tilmelde sig, hvis de ikke er det.

  • Brug af ternære operatører: Ternære operatører er især nyttige for inline conditional rendering i JSX.

function WelcomeMessage(props) {
  return (
    <div>
      {props.isLoggedIn ? (
        <h1>Welcome back!</h1>
      ) : (
        <h1>Please sign up.</h1>
      )}
    </div>
  );
}

Dette eksempel opnår det samme som det forrige, men det gøres direkte inden i JSX'en, hvilket kan være mere læsbart for mindre og mere direkte betingelser.

6.2 Skjul komponenter ved at returnere null

En vigtig ting at bemærke om conditional rendering i React er, at du kan forhindre en komponent i at blive renderet ved at returnere null fra en komponents render-metode.

  • Eksempel på at returnere null:

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

I dette eksempel vil WarningBanner kun blive renderet, hvis props.warn er sandt. Hvis det er falsk, renderes intet, hvilket effektivt skjuler komponenten.

Conditional rendering er en kraftfuld teknik i React, der gør det muligt at bygge dynamiske og responsive applikationer. Ved at integrere simpel JavaScript-logik direkte i dine komponenter, kan du nemt kontrollere, hvilke dele af din applikation der er synlige for brugeren under forskellige forhold.

7. Lister og keys

7.1 Rendere lister

At arbejde med lister er en almindelig opgave i webudvikling. I React kan lister af elementer blive rendret ved at bruge JavaScripts map() funktion til at transformere et array af data til et array af JSX-elementer.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

I dette eksempel omdannes hvert tal i arrayet numbers til et <li>-element. Nøglen til effektivt at rendere lister er brugen af key-props, som vil blive uddybet nærmere.

7.2 Brug af keys

Keys hjælper React med at identificere hvilke elementer der er ændret, tilføjet eller fjernet, hvilket kan forbedre ydeevnen ved dynamisk opdatering af lister. Keys bør gives til elementerne inde i arrayet for at give en stabil identitet.

  • Vælg passende keys: Nøglerne bør være unikke blandt søskendeelementerne i listen. Typisk vil du bruge IDs fra dine data som keys. Hvis du ikke har stabile IDs for rendrede elementer, kan du bruge elementets indeks som en sidste udvej, selvom det ikke anbefales, da det kan påvirke ydeevnen og forårsage problemer med komponentens tilstand.

const todoItems = todos.map((todo, index) =>
  // Kun brug indeks som nøgle, hvis elementerne ikke har stabile IDs
  <li key={index}>
    {todo.text}
  </li>
);

7.3 Problemer med indeks som key

Brug af indekser som keys er ikke ideelt, hvis listen kan ændres. Hvis listen reordnes eller elementer indsættes i begyndelsen, vil indekserne ændres, hvilket kan føre til yderligere genrenderinger og en fejlagtig tilstandsbehandling.

7.4 Nøgler og komponenttilstand

Når du bruger keys, er det vigtigt at forstå, at de kun er relevante inden for konteksten af den nærmeste map()-kald. De har ingen betydning for, hvordan komponenter behandler deres tilstand, da React håndterer hver komponent separat baseret på dens nøgle.

Ved at bruge keys korrekt, sikrer du, at Reacts genrenderingsproces er så effektiv som muligt, og at din applikations ydeevne optimeres, når du arbejder med lister.

8. Formularer

Formularer i React kan håndteres på en måde, der ligner håndtering af almindelige DOM-formularer, men med en vigtig React-specifik tilføjelse: kontrollerede komponenter. Ved at gøre en React-komponent til "kontrolleret", styrer du dens værdier via state og reagerer på ændringer via event handlers.

8.1 Kontrollerede komponenter

I kontrollerede komponenter er formulardata håndteret af React-komponentens tilstand. Du skriver en event handler for at opdatere tilstanden, hver gang en bruger skriver noget ind i en formular.

  • Eksempel på en kontrolleret input:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

I dette eksempel kontrolleres input-komponenten helt af React, hvilket gør data flowet mere forudsigeligt og lettere at debugge.

8.2 Ikke-kontrollerede komponenter

I modsætning til kontrollerede komponenter anvender ikke-kontrollerede komponenter ref'er til at hente værdier fra DOM-elementerne, når du har brug for dem, snarere end at gemme hver ændring i tilstanden.

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.input = React.createRef();
  }

  handleSubmit = (event) => {
    alert('A name was submitted: ' + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={this.input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

Dette eksempel viser en formular, hvor input-værdien tilgås gennem en ref ved formularindsendelse, i stedet for at hver ændring opdaterer komponentens tilstand.

8.3 Håndtering af flere inputs

Når du håndterer flere kontrollerede input-elementer, kan du tilføje en name-attribut til hver input og lade handleren vælge, hvad der skal gøres baseret på event.target.name.

handleChange(event) {
  const target = event.target;
  const value = target.type === 'checkbox' ? target.checked : target.value;
  const name = target.name;

  this.setState({
    [name]: value
  });
}

Denne teknik gør det nemt at håndtere flere forskellige inputs med en enkelt funktion, hvilket reducerer mængden af kode, der er nødvendig for at håndtere komplekse formularer.

Formularhåndtering er en essentiel del af mange webapplikationer, og ved at forstå forskellen mellem kontrollerede og ikke-kontrollerede komponenter, kan du vælge den tilgang, der bedst passer til dit projekt.

9. Avancerede React-teknikker

9.1 Lifting state up

Når flere komponenter har brug for at dele og manipulere de samme data, anbefales det at "løfte staten op" til deres nærmeste fælles forælder. Dette betyder, at du skal opbevare den delte tilstand i forælderkomponenten i stedet for at prøve at synkronisere staten mellem forskellige børnekomponenter.

class TemperatureCalculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {temperature: ''};

    this.handleTemperatureChange = this.handleTemperatureChange.bind(this);
  }

  handleTemperatureChange(temperature) {
    this.setState({temperature});
  }

  render() {
    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={this.state.temperature}
          onTemperatureChange={this.handleTemperatureChange} />
        <TemperatureInput
          scale="f"
          temperature={this.state.temperature}
          onTemperatureChange={this.handleTemperatureChange} />
      </div>
    );
  }
}

I dette eksempel håndterer TemperatureCalculator komponenten tilstanden for temperatur og passer den ned til TemperatureInput børnekomponenter.

9.2 Sammensætning vs. inheritance

I React foretrækkes sammensætning over inheritance for at genbruge kode mellem komponenter. Brug af sammensætning kan involvere børnekomponenter, render props, eller højere ordens komponenter til at bygge mere komplekse UI'er fra enkle byggesten.

  • Eksempel på brug af sammensætning:

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
      {props.children}
    </FancyBorder>
  );
}

Her bruger Dialog komponenten FancyBorder komponenten som en container, hvilket demonstrerer sammensætning.

9.3 Hooks

Hooks er en funktion i React 16.8, som lader dig bruge state og andre React-funktioner uden at skrive en klasse. De mest almindelige hooks er useState og useEffect.

  • Eksempel på brug af useState og useEffect:

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Her håndterer Example komponenten en tæller ved hjælp af useState og opdaterer dokumentets titel ved hjælp af useEffect.

9.4 Context

Context giver en måde at dele værdier som f.eks. brugerautentificering, temaer, eller sprogpræferencer på tværs af mange komponenter uden at sende props manuelt på alle niveauer af træet.

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme}>I am styled by theme context!</button>}
    </ThemeContext.Consumer>
  );
}

I dette eksempel passer App en "dark" tema værdi ned gennem Toolbar til ThemedButton ved hjælp af Context, uden at manuelt proppe den ned gennem hver komponent.

Disse avancerede teknikker giver dig mulighed for at bygge mere effektive og vedligeholdelsesvenlige React-applikationer, idet de udnytter kraftfulde mønstre og funktioner i React-biblioteket.

9.5 Error boundaries

Error boundaries er en nyttig funktion i React, der tillader en komponent at fange JavaScript-fejl hvor som helst i dens underkomponenters træ. Dette forhindrer hele appen i at crashe og giver dig mulighed for at vise en fallback UI, når der sker en fejl.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Opdater tilstanden, så den næste render viser fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // Du kan også logge fejlen til en fejlrapporteringstjeneste
    logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // Du kan render et hvilket som helst custom fallback UI
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

Brug ErrorBoundary som en wrapper omkring enhver komponent, hvor du ønsker at håndtere fejl. Hvis en fejl opstår i en af underkomponenterne, vil ErrorBoundary fange den og vise et fallback UI.

9.6 Refs og DOM

Refs giver adgang til DOM-noder direkte i React-komponenter. Dette er nyttigt for en række opgaver, som fokusering på et inputfelt, afspilning af medieindhold eller udløsning af animaer.

  • Eksempel på brug af refs:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = React.createRef();
  }

  focusTextInput = () => {
    // Eksplicit fokusere på tekst input ved hjælp af den rå DOM API
    this.textInput.current.focus();
  }

  render() {
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <button
          onClick={this.focusTextInput}>
          Focus the text input
        </button>
      </div>
    );
  }
}

I dette eksempel bruger CustomTextInput en ref til at opbevare en reference til input-elementet og fokuserer det, når en knap klikkes.

9.7 Optimering af ydeevne

React-apps kan skaleres effektivt, men nogle gange kan komplekse applikationer lide af langsomme renderinger eller forsinkelser. Brug af teknikker som React.memo, useCallback, useMemo og korrekt brug af keys kan hjælpe med at reducere antallet af unødvendige genrenderinger og dermed forbedre ydeevnen.

  • Eksempel på brug af React.memo:

const MyComponent = React.memo(function MyComponent(props) {
  /* render ved hjælp af props */
});

React.memo er en higher order component, som kun tillader komponenten at opdatere, hvis dens props har ændret sig, hvilket er nyttigt for at undgå dyre genrenderinger i komponenter, der modtager de samme props med identiske værdier over gentagne renders.

Disse avancerede teknikker i React giver dig værktøjer til at skrive mere robuste, vedligeholdelsesvenlige og performante webapplikationer. Ved at mestre disse metoder kan du udnytte Reacts fulde potentiale og bygge apps, der er både hurtige og pålidelige.

9.8 Context API for dybere statshåndtering

React's Context API tillader en effektiv måde at dele værdier som globale data (f.eks., tema, brugerpræferencer, autentificering) på tværs af en komponenttræ uden at skulle manuelt sende props på hvert niveau. Dette er særligt nyttigt for dybt nestede komponenter.

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme}>I am styled by theme context!</button>}
    </ThemeContext.Consumer>
  );
}

I dette eksempel defineres en ThemeContext med en standardværdi 'light'. App-komponenten bruger derefter ThemeContext.Provider til at angive temaet til 'dark', som så anvendes i ThemedButton via ThemeContext.Consumer.

9.9 Brug af Higher Order Components (HOCs)

Higher Order Components er en avanceret teknik i React for genbrug af komponentlogik. En HOC er en funktion, der tager en komponent og returnerer en ny komponent. De bruges ofte til at tilføje ekstra funktionalitet til eksisterende komponenter.

function withSubscription(WrappedComponent, selectData) {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.handleChange = this.handleChange.bind(this);
      this.state = {
        data: selectData(DataSource, props)
      };
    }

    componentDidMount() {
      // ... Tilføjer event listeners eller andet setup
    }

    componentWillUnmount() {
      // ... Fjerner event listeners eller andet cleanup
    }

    handleChange() {
      this.setState({
        data: selectData(DataSource, this.props)
      });
    }

    render() {
      return <WrappedComponent data={this.state.data} {...this.props} />;
    }
  };
}

Denne HOC withSubscription kunne bruges til at håndtere abonnering på datakilder og videregive data til en komponent som en prop.

9.10 Brug af Hooks for sideeffekter

Hooks tillader funktionelle komponenter at håndtere sideeffekter, interne statshåndtering og mere. useEffect er en Hook, der gør det muligt at udføre sideeffekter i funktionelle komponenter. Det kan bruges til at håndtere abonnementer, timere, API-kald, og mere.

  • Eksempel på brug af useEffect:

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Du klikkede ${count} gange`;

    return () => {
      document.title = 'React App';
    };
  }, [count]);  // Kun genkør effekten hvis count ændres

  return (
    <div>
      <p>Du klikkede {count} gange</p>
      <button onClick={() => setCount(count + 1)}>
        Klik mig
      </button>
    </div>
  );
}

Her opdaterer useEffect dokumentets titel, når count ændres, og nulstiller den, når komponenten fjernes.

Disse avancerede teknikker styrker React's fleksibilitet og udtryksfuldhed, og giver udviklere kraftfulde værktøjer til at bygge komplekse og højt optimerede applikationer.

10. React Router

React Router er et standardbibliotek i React-økosystemet, der anvendes til at håndtere navigation og routing i React-applikationer. Det giver mulighed for at opbygge en single-page application (SPA) med navigation, der ligner multi-page websites, hvor URL-adressen ændres uden at siden genindlæses.

React Router tilbyder flere komponenter som <BrowserRouter>, <Route>, <Link>, <Switch>, og <Redirect> til at håndtere routing. Disse komponenter giver dig mulighed for at definere navigationsstrukturer, link til forskellige dele af din applikation, og vælge visningen baseret på URL'en.

  • Opsætning af React Router:

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

I dette eksempel bruges <Switch> til at eksklusivt vælge en <Route> baseret på URL'en. <Route> komponenterne definerer hvilken komponent, der skal renderes, baseret på den aktuelle sti.

10.1 Navigation og Links

For at oprette links i din applikation uden at genindlæse siden, bruger React Router <Link> komponenten, som forhindrer standard browseropførsel og opdaterer browserens URL-bar.

  • Eksempel på brug af Link:

import { Link } from 'react-router-dom';

function Navbar() {
  return (
    <nav>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/about">About</Link>
        </li>
        <li>
          <Link to="/users">Users</Link>
        </li>
      </ul>
    </nav>
  );
}

Her skaber <Link> komponenter navigerbare links, der ikke genindlæser siden, men opdaterer visningen baseret på den valgte rute.

10.2 Dynamisk routing

React Router understøtter også dynamisk routing, hvor parametre kan indgå i URL-stien og derefter tilgås i din komponent.

<Route path="/user/:id" component={User} />

I dette eksempel vil en URL som /user/123 matche ovenstående rute, hvor 123 vil være tilgængelig som en parameter i User-komponenten.

10.3 Programmér navigation

Ud over at bruge <Link> til at ændre ruter, kan du programmært navigere med React Router ved hjælp af historieobjektet, som du kan få adgang til gennem useHistory hook.

import { useHistory } from 'react-router-dom';

function HomeButton() {
  let history = useHistory();

  function handleClick() {
    history.push('/home');
  }

  return (
    <button type="button" onClick={handleClick}>
      Go home
    </button>
  );
}

I dette eksempel navigerer knappen brugeren til /home stien, når den klikkes, ved at tilføje den nye lokation til browserens historikstak.

React Router er et kraftfuldt værktøj, der gør det muligt for React-udviklere at bygge komplekse navigationsstrukturer og forbedre brugeroplevelsen i single-page applikationer.

11. Redux

Redux er en populær bibliotek til tilstandsstyring for JavaScript-applikationer, ofte anvendt sammen med React, men det kan bruges med ethvert andet JavaScript-framework eller bibliotek. Det er især nyttigt for store applikationer med komplekse datastrømme og mange interaktioner, hvor flere komponenter kræver adgang til den samme applikationstilstand.

Redux centraliserer applikationens tilstand i et enkelt "store", hvilket gør det lettere at holde styr på tilstandsændringer over tid. I Redux er al tilstandsændring logik skrevet i form af "reducers" – funktioner, der tager den forrige tilstand og en "action" og returnerer en ny tilstand.

  • Eksempel på en Redux reducer:

function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

I dette eksempel håndterer counter reduceren to aktionstyper: INCREMENT og DECREMENT. Reduceren opdaterer tilstanden baseret på hvilken handling der er udført.

11.1 Actions og Action Creators

Actions i Redux er JavaScript-objekter, der beskriver ændringer i applikationen. De skal have en type-egenskab, der angiver typen af handling, der skal udføres. Action creators er funktioner, der returnerer en action.

  • Eksempel på en action og en action creator:

function increment() {
  return { type: 'INCREMENT' };
}

function decrement() {
  return { type: 'DECREMENT' };
}

Disse funktioner, increment og decrement, er action creators, der skaber og returnerer actions, som kan dispatches til store.

11.2 Anvendelse af Redux

For at integrere Redux med React anvendes react-redux biblioteket, som tilbyder Provider og connect funktioner til at binde Redux store med React-komponenter.

  • Opsætning af Redux med React:

import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
import App from './App';

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Provider-komponenten omslutter hele applikationen og gør Redux store tilgængelig for alle nestede komponenter.

11.3 Middleware og asynkrone aktioner

Redux understøtter middleware, som giver mulighed for at udvide Redux med brugerdefineret funktionalitet, for eksempel for at håndtere asynkrone operationer. Det mest populære middleware til Redux er Redux Thunk, som gør det muligt at skrive action creators, der returnerer en funktion i stedet for en action.

  • Eksempel på anvendelse af Redux Thunk:

function fetchData() {
  return (dispatch) => {
    fetch('<https://api.example.com/data>')
      .then(response => response.json())
      .then(data => dispatch({ type: 'RECEIVE_DATA', data }));
  };
}

I dette eksempel henter fetchData asynkront data og dispatches en action, når data er modtaget.

Redux tilbyder en robust løsning til håndtering af applikationstilstande, hvilket gør det nemmere at udvikle vedligeholdelige og forudsigelige webapplikationer ved at følge strenge regler for hvordan tilstanden opdateres og overføres gennem applikationen.

13. React og TypeScript

13.1 Integrering af TypeScript i React

TypeScript er et populært, typet overbygning til JavaScript, der tilføjer statiske typer og avancerede objektorienterede funktioner. Når det anvendes sammen med React, forbedrer TypeScript pålideligheden og vedligeholdelsen af kode ved at tilføje typekontroller, hvilket gør det lettere at udvikle store eller komplekse applikationer.

13.2 Opsætning af et React-projekt med TypeScript

Oprettelse af et nyt React-projekt med TypeScript kan nemt gøres ved hjælp af Create React App, som understøtter TypeScript ud af boksen.

  • Start et nyt React + TypeScript projekt:

npx create-react-app my-app --template typescript

Dette kommando initierer et nyt projekt, inkluderer TypeScript konfigurationen, og opsætter alt nødvendigt for at begynde at arbejde med React og TypeScript.

13.3 Definere komponenter med TypeScript

Når du definerer React-komponenter med TypeScript, kan du specificere typer for props og state, hvilket giver en robust typekontrol gennem hele komponentens livscyklus.

  • Eksempel på en funktionel komponent med props:

type AppProps = {
  title: string;
  isActive: boolean;
};

const App: React.FC<AppProps> = ({ title, isActive }) => {
  return <div>{isActive ? title : "Inactive"}</div>

Dette eksempel viser en funktionel komponent, hvor propstyperne er defineret klart, hvilket hjælper TypeScript med at verificere korrekt brug af komponenten i applikationen.

13.4 Brug af Hooks med TypeScript

TypeScript forbedrer brugen af React Hooks ved at tillade typer at blive angivet for hooks som useState og useEffect, hvilket giver yderligere sikkerhed i håndteringen af applikationstilstand.

  • Eksempel på useState med TypeScript:

const [isOnline, setIsOnline] = useState<boolean>(false);

Her angiver useState-typen boolean, hvilket sikrer, at isOnline og setIsOnline håndterer boolean værdier korrekt.

13.5 Fordele ved at bruge TypeScript med React

Brug af TypeScript i React-projekter tilbyder flere fordele:

  • Forbedret kodekvalitet: Stærke typekontroller hjælper med at identificere mange potentielle fejl under udviklingen, før softwaren når produktion.

  • Bedre værktøjsstøtte: Moderne IDE'er og redaktører tilbyder bedre navigation og autokomplet med TypeScript, hvilket forbedrer udviklerens effektivitet.

  • Lettere refaktorering: Sikker refaktorering af kode bliver lettere, da ændringer, der bryder typekontrakter, hurtigt kan identificeres.

13.6 Udfordringer

Selvom TypeScript tilføjer mange fordele, kommer det også med en læringskurve. Udviklere skal være fortrolige med TypeScript's type system, og der kan være en initial opsætnings- og konfigurationsoverhead, især i eksisterende projekter, der overgår til TypeScript.

Integrering af TypeScript i React-applikationer er en investering, der kan øge produktiviteten og sikkerheden i applikationsudviklingen, og gøre det lettere at vedligeholde og skalere applikationer over tid.

14. Best practices

14.1 Kodekvalitet og vedligeholdelse

At opretholde høj kodekvalitet og god kodevedligeholdelse er afgørende for at sikre, at React-applikationer forbliver skalérbare og nemme at administrere. Her er nogle best practices for at opnå dette:

  • Komponentopdeling: Opdel UI i genanvendelige, små komponenter, der hver især håndterer en specifik funktion. Dette fremmer genbrug og gør koden lettere at teste og vedligeholde.

  • Klare ansvarsområder: Hver komponent bør have et veldefineret ansvarsområde. Undgå at gøre komponenter for "smarte" eller overbelastede med logik.

  • Prop-types og TypeScript: Brug prop-types eller TypeScript til at definere og validere typer af props, som komponenter modtager. Dette øger robustheden og forudsigeligheden af din kode.

14.2 Statehåndtering

Effektiv håndtering af tilstand er kritisk i React-applikationer:

  • Lift state up: Når flere komponenter deler den samme tilstand, bør du løfte tilstanden op til deres nærmeste fælles forælder. Dette centraliserer tilstanden og letter kommunikationen mellem komponenter.

  • Brug Redux omhyggeligt: Overvej Redux eller en anden tilstandshåndteringsbibliotek, når applikationen bliver for stor eller kompleks til enkel prop-drilling eller React Context er utilstrækkelig.

14.3 Ydeevneoptimering

Ydeevne er en anden kritisk faktor, især i større applikationer:

  • Memoization: Brug React.memo, useMemo, og useCallback for at forhindre unødvendige genrenderinger ved at huske tidligere output baseret på de samme inputs.

  • Lazy loading: Brug React.lazy for dynamisk import af komponenter, der ikke er nødvendige ved den første load, hvilket kan reducere starttidspunktet.

14.4 Accessibility (Tilgængelighed)

Tilgængelighed bør være en integreret del af design og udvikling:

  • Semantiske HTML-elementer: Brug passende HTML5-elementer, som hjælper med at guide skærmlæsere og andre assistive teknologier.

  • ARIA-attributter: Brug ARIA-roller og attributter, når semantiske HTML-elementer ikke er tilstrækkelige.

14.5 Testing

Sikre, at applikationen er stabil og fejlfri gennem omfattende testning:

  • Enhedstest: Test individuelle komponenter for at sikre, at de fungerer som forventet uafhængigt.

  • Integrationstest: Test integrationen mellem flere komponenter og deres samspil med tilstandshåndtering.

  • E2E-test: Simuler brugerens end-to-end arbejdsflow for at sikre, at hele applikationen fungerer som forventet.

14.6 Udviklerværktøjer

Benyt avancerede værktøjer og udvidelser som React Developer Tools til at inspicere og debugge React-komponenter. Disse værktøjer kan give indsigt i komponenttræer, tilstandsændringer og ydeevneproblemer.

Ved at følge disse best practices kan udviklere opbygge robuste, effektive og vedligeholdelsesvenlige React-applikationer, der er klar til produktion og skalerbare til fremtidens krav.

15. Ressourcer og samfund

15.1 Læringsressourcer

React-økosystemet er støttet af et omfattende udvalg af læringsmaterialer og dokumentation, der kan hjælpe udviklere på alle niveauer med at forbedre deres færdigheder og forståelse af biblioteket.

  • Officiel dokumentation: Reacts officielle dokumentation (reactjs.org) er en omfattende ressource, der dækker alle aspekter af biblioteket, fra grundlæggende begreber til avancerede teknikker.

  • Online kurser: Platforme som Udemy, Coursera, og freeCodeCamp tilbyder kurser i React, der spænder fra begynder til avancerede niveauer.

  • Video-tutorials: YouTube-kanaler og andre videoplatforme tilbyder gratis ressourcer, der demonstrerer specifikke teknikker og bedste praksisser.

15.2 Community support

React har et levende og støttende samfund, som er en uvurderlig ressource for både nye og erfarne udviklere.

  • Stack Overflow: En platform, hvor man kan stille spørgsmål og få svar fra andre udviklere.

  • GitHub: Reacts kildekode og mange tredjepartsbiblioteker er tilgængelige på GitHub, hvor udviklere kan bidrage til open source-projekter og følge udviklingen.

  • Reddit og sociale medier: Fora som Reddit, Twitter, og LinkedIn grupper tilbyder steder at dele viden, diskutere problemer, og netværke med andre React-udviklere.

15.3 Konferencer og Meetups

Deltagelse i konferencer og lokale meetups kan give værdifulde læringsmuligheder og chancen for at møde andre i industrien.

  • React konferencer: Arrangementer som React Conf og ReactEurope samler ledende eksperter og entusiaster for at dele deres viden og erfaringer.

  • Meetup-grupper: Lokale meetup-grupper tilbyder regelmæssige møder, workshops og hackathons, hvor man kan lære af og samarbejde med andre udviklere.

15.4 Open Sourceprojekter

Bidrag til open source-projekter er en fremragende måde at lære React på, forbedre dine udviklingsevner og give tilbage til fællesskabet.

  • Bidrage til React: Udviklere opfordres til at bidrage til React selv, hvad enten det handler om at forbedre dokumentationen eller at løse issues.

  • Tredjepartsbiblioteker: Der findes et utal af React-relaterede biblioteker og projekter, der søger bidrag fra fællesskabet.

15.5 Kontinuerlig læring

Teknologier udvikler sig konstant, og det samme gælder for React-økosystemet. Det er vigtigt for udviklere at holde sig opdateret med de nyeste ændringer, features og bedste praksisser.

  • Abonner på blogs og nyhedsbreve: Følg eksperter og læs regelmæssigt blogs og nyhedsbreve for at holde sig ajour med de seneste trends og opdateringer.

  • Deltag i kodningsudfordringer: Online platforms som CodeSignal og LeetCode tilbyder kodningsproblemer, der kan hjælpe med at skærpe dine færdigheder og lære nye tilgange.

Ved at udnytte disse ressourcer og engagere sig i React-samfundet, kan udviklere bygge stærke netværk, avancere deres karrierer og forblive på forkant med moderne webudvikling.

16. Konklusion

React er et utroligt kraftfuldt og alsidigt JavaScript-bibliotek, der har revolutioneret måden, vi tænker på at bygge brugergrænseflader på. Fra små startprojekter til store skala enterprise-applikationer, Reacts komponentbaserede arkitektur tilbyder en effektiv, deklarativ og fleksibel tilgang til udvikling af webapplikationer.

Med et robust økosystem, der omfatter værktøjer som Redux for tilstandsstyring, React Router for navigation, og et væld af tredjeparts biblioteker, har udviklere adgang til alt det nødvendige for at bygge dynamiske og interaktive applikationer. Integrationen af TypeScript tilføjer yderligere styrker til type-sikkerhed, hvilket gør React endnu mere robust og vedligeholdelsesvenlig.

Det aktive og støttende React-samfund spiller en afgørende rolle i bibliotekets vedvarende popularitet og udvikling. Ved at deltage i dette samfund, uanset om det er gennem online fora, lokale meetups eller store konferencer, kan udviklere dele viden, løse problemer og finde nye muligheder for samarbejde.

Udnyttelsen af de bedste praksisser og fortsat uddannelse i nye funktioner og mønstre er nøglen til at mestre React. Ved at holde sig ajour med de seneste trends og teknologier, kan React-udviklere sikre, at deres færdigheder forbliver relevante og efterspurgte i den hurtigt udviklende verden af webudvikling.

Konklusionen er, at React ikke kun er et bibliotek til at bygge applikationer; det er en gateway til at bygge moderne, effektive og skalerbare løsninger, der kan tilpasse sig fremtidige teknologiske fremskridt og brugerkrav. For nye og erfarne udviklere, der ønsker at være i forkant med moderne webteknologier, er React et uundværligt redskab i udviklingsarsenalet.

Har du brug for en React udvikler til dit næste IT-projekt? Hos Better Developers hjælper vi dig med at finde den rette udvikler til lige netop dine behov. Læs om React konsulenter hos Better Developers her.