# Context

In een React applicatie wordt data van het bovenste component doorgegeven naar het onderste component aan de hand van props. Dit is mogelijk in een applicatie waar de component structuur niet heel diep is, maar naar mate de applicatie groeit, groeit meestal ook de diepte van je componenten structuur. Je zal dan vaak een prop verschillende niveau's diep moeten doorgeven.&#x20;

Stel dat we een light theme en een dark theme willen ondersteunen in onze applicatie. Elk component heeft deze prop nodig want elk component moet zijn UI aanpassen als de theme light of dark is.&#x20;

```typescript
const App = () => {
    ...
    <ListPage games={games} handleAdd={handleAdd} theme={'light'}/>
    ....
}
```

```typescript
interface ListPageProps {
  games: Game[],
  handleAdd: (game: Game) => void,
  theme: string
}

const ListPage = ({games,handleAdd, theme} : ListPageProps) => {
  return (
    <div>
      <List games={games} theme={theme}/>
      <InputView onAdd={handleAdd} theme={theme} />
    </div>
  );
}
```

```typescript
interface ListProps {
  games: Game[],
  theme: string
}

const List = ({ games, theme }: ListProps) => {
  return (
    <div className={styles.gamesList}>{games.map((game: Game) => {
      return <ListItem game={game} theme={theme}/>
    })}
    </div>
  );
}
```

```typescript
interface ListItemProps {
  game: Game,
  theme: string,
}

const ListItem = ({ game, theme }: ListItemProps) => {
  ...
}

```

Schematisch ziet dat er als volgt uit:

![](https://846376556-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-McTNvdIuKynd-zW5FrJ%2F-Mfbla7zKnMw0afdQWqk%2F-MfbnkIwmmluuEXE6IJq%2FUntitled%20Diagram%20\(1\).svg?alt=media\&token=7ff688af-e2d6-433b-96fb-97bbaeab70aa)

Je ziet dat zelfs voor een kleine applicatie, zoals als degene die we in deze cursus hebben gemaakt, dat deze `theme` prop al moeten doorgeven doorheen 3 niveaus van componenten. Bij grotere applicaties gaat dit nog veel erger worden. Daarom heeft React voor de `Context` API gezorgd. Dit is een manier om data te gaan delen doorheen componenten zonder door heel de structuur te moeten doorgegeven worden.

Het eerste wat we moeten doen is een `Context` aanmaken aan de hand van de `createContext`

```typescript
export const ThemeContext = React.createContext({mode: 'light'});
```

Je moet altijd een default waarde meegeven aan de context. Deze default waarde wordt enkel gebruikt als er geen provider aanwezig is bovenaan in de component structuur. We geven hier een object met een `mode` property. Dus in ons geval zal onze layout dus standaard in light mode staan.

Nu moeten we een `Provider` maken van onze `ThemeContext` zodat we de values kunnen meegeven die we in de componenten willen gebruiken. De provider moet rond de bovenste component staan die onze context willen gebruiken.

```typescript
return (
  <ThemeContext.Provider value={{mode: 'light'}}>
    <Router>
      ...
    </Router>
  </ThemeContext.Provider>
```

Nu kan je de values van de `ThemeContext` provider opvragen aan de hand van de `useContext` hook. Als de `mode` dark is dan voegen we een extra className toe zodat we in ons css bestand een `gameCardDark` class kunnen maken.

```typescript
import { ThemeContext } from 'components/App/App';
import { useContext } from 'react';
import { Link } from 'react-router-dom';
import { Game } from 'types';
import styles from './List.module.css'

interface ListItemProps {
  game: Game
}

const ListItem = ({ game }: ListItemProps) => {
  const {mode} = useContext(ThemeContext);

  return (
    <Link to={`/detail/${game.id}`}>
      <div key={game.id} className={`${styles.gameCard} ${mode === 'dark' ? styles.gameCardDark : ''}`}>
        <div>{game.name}</div>
        <div>{game.releaseYear}</div>
        <div>{game.sales}</div>
      </div>
    </Link>
  )
}

export default ListItem;
```

Je ziet nu dat elk component toegang heeft tot de `mode` variabele die we in de context hebben aangeboden zonder dat we deze moeten doorgeven doorheen de component hierarchie.

We kunnen ook handler functies toevoegen in onze `ThemeContext` zodat we ook van elk component de `mode` kunnen aanpassen. We voegen nu aan de createContext functie een `setMode` functie toe. We moeten hier een default value voor aanbieden, op dit moment hebben we nog geen handler dus we geven een lege functie mee.

```typescript
export const ThemeContext = React.createContext({mode: 'light', setMode: (mode: string) => {}});
```

We maken nu in onze `App` component een state aan die de `mode` bijhoudt zodat we deze kunnen aanpassen.

```typescript
const [mode, setMode] = useState('light');
```

Nu geven we de `setMode` functie mee aan de provider

```typescript
<ThemeContext.Provider value={{mode: mode, setMode: setMode}}>
```

Vanaf nu is de `setMode` functie overal beschikbaar in elk component die deze context gebruikt. We kunnen nu de `Header` component uitbreiden met een `ModeButton` component die gebruik kan maken van de `mode` en `setMode` van de context. We maken hier gebruik van een FontAwesome icon. Dit is een grote verzameling van icons die worden aangeboden om in projecten te gebruiken. Deze kan je installeren door&#x20;

```
npm install --save @fortawesome/fontawesome-svg-core
npm install --save @fortawesome/free-solid-svg-icons
npm install --save @fortawesome/react-fontawesome
```

uit te voeren. We maken ook nog een nieuwe component `ModeButton` in een nieuwe component directory `components/ModeButton`

```typescript
import React, { useContext } from 'react';

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons'
import { ThemeContext } from 'components/App/App';
import styles from './ModeButton.module.css'

const ModeButton = () => {
  const {mode, setMode} = useContext(ThemeContext);
  return (
    <div className={styles.modeToggle}>
      
      {mode === 'dark' ? 
        <button onClick={() => {setMode('light')}}><FontAwesomeIcon icon={faSun} className={styles.modeIcon}/></button> :
        <button onClick={() => {setMode('dark')}}><FontAwesomeIcon icon={faMoon} className={styles.modeIcon}/></button>
      }
    </div>
  )
}

export default ModeButton;


```

We tonen aan de hand van de huidige mode nu een button die een zon icon toont als het dark mode is en een maan icon als het light mode is. We zetten hier een `onClick` listener op en roepen in deze listener de `setMode` functie op. Dit is de `setMode` functie die we hebben meegegeven met de `ThemeContext` provider.&#x20;

We kunnen de button stylen met een css module te maken voor de `ModeButton` component.

```css
.modeToggle {
  display: flex;
  align-items: center;
  margin-left: auto;
  padding-right: 20px;
}

.modeToggle button {
  background-color: transparent;
  border: none;
}

.modeIcon {
  color: white
}

.modeIcon:hover {
  color: lightblue
}
```

Nu kunnen we deze in de `Header` component plaatsen en dan hebben we een manier om de dark mode en de light mode te triggeren.&#x20;

Er zijn nog veel andere voorbeelden waar `Context` handig is om je applicatie structuur te verbeteren. Maar zorg er wel voor dat je deze niet te veel begint te gebruiken. Zolang je props niet op veel verschillende plaatsen moeten gebruikt worden of niet door verschillende componenten heen moeten doorgegeven worden is het soms beter om toch props te blijven gebruiken. `Context` is geen alternatief voor props, dus gebruik het zeker niet om alles globaal beschikbaar te maken.
