Direct, Indirect, Redirect: React Props, Context, and State as Inputs
Tags: discuss, react, javascript, typescript
Published: 2019-12-06 20:24:30

---
title: Direct, Indirect, Redirect: React Props, Context, and State as Inputs
published: true
description: How I make sense of Props, Context, and State in React
tags: discuss, react, javascript, typescript
---

# tl;dr

Functions are about inputs, side effects, and outputs. React component functions are no different. How do you think about props, state, and context in terms of inputs, side effects, and outputs? What follows is a model I find useful in talking with students. I'd love to hear how it sits with you, or if it brings up any questions!

# Intro

With the latest versions of React (>16.8), it's possible to model all aspects of a client application as a problem of functions and composing functions. Hooks provide a basic functional abstraction for state, side effects outside of the render cycle, and retrieving data from various contexts in the React tree. 

Functions are a set of inputs, side effects, and an output. React introduces many new ideas, but they still map well to more basic ideas about how functions work. Let's take a look at how that mapping looks!

# Props: Direct Input

Props are the direct inputs into a function. They are passed in React together as an object argument to the component function. 

Here we see an example of a "Score" display in Typescript that takes a `number` prop called `score`. It renders that score into a string, and that string into a `span` element. Eventually, our inputs will be represented in some form in the output of our combined component functions, and in the rendered result!

```tsx
// score.tsx

import React from 'react'

export function Score({ score: number }) {
  return <span>Your score is {score}</span>
}
```

# Context: Indirect Input

Context is another available input into our React component functions. Where as props are direct, context is an indirect way to pass data to our components. With context, we pass a value once as a prop to a provider above our components in the React tree. This provider then, through React, passes the value to its consumers within our components.

Here is an example in Typescript along the same lines, with a `GameHeader` pulling a `Game` object from the context, and rendering a the score. Notice how the same value passes from context, and becomes a prop. We'll see how to update this value later when talking about state!

```tsx
// game.tsx

import React from 'react'

export type Game = { score: number }

export const GameContext = React.createContext<Game>({ score: 0 })
```
```tsx
// game_header.tsx

import React from 'react'
import Score from './score'
import {GameContext} from './game'

function GameHeader() {
  const { score } = React.useContext(GameContext);

  return <header><Score score={score} /></header>
}
```

# State: Redirect Input

Finally, we have state. State is also an input, but it is also a side effect. That's why the hooks for state, `useState` and `useReducer`, both return a tuple of a value and a function. The value is the input, and the function performs the side effect.

> Hint: When you see a function that doesn't return a value (in Typescript something like `() => void`) chances are it performs a side effect. That's not to say that functions that return values can't perform side effects, but those that don't most likely either do nothing or perform a side effect.

The side effect in this case triggers the component to re-render and receive the updated value. This allows you to _redirect_ values within your application. Here we see a more complete example, where the `score` is stored, and updated each time the user clicks a `button`:

```tsx
// app.tsx

import React from 'react'
import {GameContext} from './game'
import {GameHeader} from './game_header'

function App() {
  const [game, incrementScore] = React.useReducer(({ score }) => ({
    score: score + 1
  }), { score: 0 });

  return (
    <GameContext.provider value={game}>
      <GameHeader />
      <button onClick={() => incrementScore()}>Click Here!</button>
    </GameContext.provider>
  )
}
```
Notice how the side effect function ends up composed into our output (in the `onClick` handler) along with the value. That side effect redirects the click event into our stateful value, and re-inputs that into our component tree. Cool!

So how does this fit into your mental framework? I'd love to hear!