---
title: Bitovi Academy - Context Hooks
description: Learn how to manage global app state with context hooks.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

[Bitovi](https://www.bitovi.com/?hsLang=en-us)

- [Services](https://www.bitovi.com/services?hsLang=en-us)
- [Client Work](https://www.bitovi.com/client-work?hsLang=en-us)
- [Our Team](https://www.bitovi.com/about?hsLang=en-us)
- [Open Source](https://www.bitovi.com/open-source?hsLang=en-us)
- [Blog](https://www.bitovi.com/blog?hsLang=en-us)
- [Academy](https://www.bitovi.com/academy/?hsLang=en-us)

[Contact Us](https://www.bitovi.com/contact?hsLang=en-us)

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react-vite.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us) 
    - [ Setting Up Your Environment ](https://www.bitovi.com/academy/learn-react/setting-up-your-environment.html?hsLang=en-us)
    - [ Introduction to JSX ](https://www.bitovi.com/academy/learn-react/intro-to-jsx.html?hsLang=en-us)
    - [ What are React Components ](https://www.bitovi.com/academy/learn-react/components.html?hsLang=en-us)
    - [ Props: Component Arguments ](https://www.bitovi.com/academy/learn-react/props.html?hsLang=en-us)
    - [ Styling in React ](https://www.bitovi.com/academy/learn-react/styling-in-react.html?hsLang=en-us)
    - [ Stateful Hooks ](https://www.bitovi.com/academy/learn-react/stateful-hooks.html?hsLang=en-us)
    - [ Controlled vs Uncontrolled ](https://www.bitovi.com/academy/learn-react/controlled-vs-uncontrolled.html?hsLang=en-us)
    - [ Optimization Hooks ](https://www.bitovi.com/academy/learn-react/optimization-hooks.html?hsLang=en-us)
    - [ Managing Complex State ](https://www.bitovi.com/academy/learn-react/managing-complex-state.html?hsLang=en-us)
    - [ Context Hooks ](https://www.bitovi.com/academy/learn-react/context-hooks.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Context Hooks `page`

Learn how to manage global app state with context hooks.

## The Prop Drilling Problem

A single component can take as many props as you want to give it, but just like arguments in functions, it’s a good idea to limit this number, as more props makes for a more confusing and harder to test component. [This discussion here](https://stackoverflow.com/questions/37695557/react-are-there-respectable-limits-to-number-of-props-on-react-components), perfectly summarizes why it’s a bad idea and considered a ["code smell"](https://martinfowler.com/bliki/CodeSmell.html).

However, this can be difficult to do when you have a lot of data to pass through your component tree. Consider the following hierarchy with a few "drilled props". Lets imagine that the `Theme`, `Domain` and `RootUrl` are decided within the `App` component, but are **only** needed within the `ButtonText` component. That is to say, `Dashboard` and `Button` have no business related to any of those props.

```
──┬ App(Theme, Domain, RootUrl)
  └─┬ Dashboard(Theme, Domain, RootUrl)
    |─┬ Button(Theme, Domain, RootUrl)
    │ └── ButtonText(Theme, Domain, RootUrl)
    └─┬ Button(Theme, Domain, RootUrl)
      └── ButtonText(Theme, Domain, RootUrl)
```

Without concerning ourselves with what exactly each of the props does, we can see the problem. Every piece of global state must be propagated through the entire hierarchy. As a result, every component would look something like this:

```
function Component1({ Theme, Domain, RootUrl }) {
  return <Component2 Theme={Theme} Domain={Domain} RootUrl={RootUrl}>
}
```

It is possible to re-write it using the spread operator, but what you gain in conciseness, you lose in clarity and performance. **Avoid writing components like this!**

```
function Component1(props) {
  return <Component2 {...props} >
}
```

In this case, it doesn’t matter if `Component1` even needs the `Theme` prop; it will always require it simply because `Component2` might require it. Initially, this was solved using libraries such as [Redux](https://redux.js.org/). These libraries would work by wrapping each component in a connector Higher-order Component (HoC) which would automatically pass in any required props. Today, we solve this problem using React’s Context Providers and Consumers.

## What is Context?

One way to think about Contexts is an additional set of props which are passed transparently through React’s internals instead of arguments. It involves three parts:

1. **The Context:** Think of the context like a box of things. The box needs to be available to all who want to use it.
2. **The Provider:** The provider puts things into the box. Whatever data it handles is only available to its children.
3. **The Consumer:** The consumer takes things out of the box. It can only access the providers which are above it in the component hierarchy.

## The Context API

### Writing a Context

Creating a Context is as easy as calling `createContext()` and supplying it a default value.

```
import React, { createContext } from 'react';

const defaultValue = 'Unknown';
const UsernameContext = createContext(defaultValue);
```

The default value is what the **Consumers** will get if they have no available **Provider**. This is often used more in testing than in production.

### Writing a Provider

The provider component is exposed by the context. It is always accessible via `ContextName.Provider` and requires a single prop named `value`. This prop will be provided to all of its **Consumers**.

Any components we render inside of the provider will be able to access the information in the `value` prop, no matter how deeply nested they are in the component tree. This eliminates the need for prop drilling where a single prop would need to be passed down through multiple components.

```
import React, { createContext } from 'react';

const defaultValue = 'Unknown';
const UsernameContext = createContext(defaultValue);

function App() {
  let [username, setUsername] = React.useState('No-name');

  return (
    <UsernameContext.Provider value={username}>
      <WhoAmI />
    </UsernameContext.Provider>
  );
}
```

### Writing a Consumer

The consumer is similarly exposed by the context under `ContextName.Consumer`. It allows us to extract the value supplied to a producer above it using a callback.

```
import React, { createContext } from 'react';

const defaultValue = 'Unknown';
const UsernameContext = createContext(defaultValue);

function App() {
  let [username, setUsername] = React.useState('No-name');

  return (
    <UsernameContext.Provider value={username}>
      <WhoAmI />
    </UsernameContext.Provider>
  );
}

function WhoAmI() {
  return (
    <UsernameContext.Consumer>
      {(value) => {
        return <span>{value}</span>;
      }}
    </UsernameContext.Consumer>
  );
}
```

### Updating the Context

As discussed before, Contexts are a lot like props. Their only difference is the method through which they are passed. To update them, we need to update the value that is passed into the **Provider**. Consider the following changes to make it possible:

```
import React, { createContext } from 'react';

const defaultValue = {
  username: 'Unknown',
  setUsername: () => new Error('Not in provider'),
};
const UsernameContext = createContext(defaultValue);

function App() {
  let [username, setUsername] = React.useState('No-name');

  return (
    <UsernameContext.Provider
      value={{ username: username, setUsername: setUsername }}
    >
      <WhoAmI />
    </UsernameContext.Provider>
  );
}

function WhoAmI() {
  return (
    <UsernameContext.Consumer>
      {(value) => {
        return (
          <>
            <span>{value.username}</span>
            <button onClick={() => value.setUsername('Mike')}>
              My Name is Mike
            </button>
            <button onClick={() => value.setUsername('Kyle')}>
              My Name is Kyle
            </button>
          </>
        );
      }}
    </UsernameContext.Consumer>
  );
}
```

We have made three changes to our code:

1. We have changed the shape of our context data from a String, to an Object. This was necessary to pass multiple properties within the same Context.
2. We included the `setUsername` function in the value of our Provider.
3. We added 2 buttons to call the `setUsername` function in the `WhoAmI` component.

## Context with Hooks

With the introduction of hooks, React also brought us the `useContext` hook. It allows us to consume Contexts without callbacks. In order to use it, pass the Context object to the `useContext` hook.

The above example could be re-written to use the `useContext` hook as follows:

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

const defaultValue = {
  username: 'Unknown',
  setUsername: () => new Error('Not in provider'),
};
const UsernameContext = createContext(defaultValue);

function App() {
  let [username, setUsername] = React.useState('No-name');

  return (
    <UsernameContext.Provider
      value={{ username: username, setUsername: setUsername }}
    >
      <WhoAmI />
    </UsernameContext.Provider>
  );
}

function WhoAmI() {
  const value = useContext(UsernameContext);

  return (
    <>
      <span>{value.username}</span>
      <button onClick={() => value.setUsername('Mike')}>My Name is Mike</button>
      <button onClick={() => value.setUsername('Kyle')}>My Name is Kyle</button>
    </>
  );
}
```

The method for consuming contexts has now shifted from callbacks from within JSX to simple, procedural function calls. This has the benefit of making the code flatter, and easier to read. Additionally, using multiple consumers becomes significantly cleaner.

#### Without Hooks:

```
return (
  <FooContext.Consumer>
    {(foo) => (
      <BarContext.Consumer>
        {(bar) => (
          <BazContext.Consumer>
            {(baz) => (
              <span>
                {foo} {bar} {baz}
              </span>
            )}
          </BazContext.Consumer>
        )}
      </BarContext.Consumer>
    )}
  </FooContext.Consumer>
);
```

#### With Hooks

```
const foo = useContext(FooContext);
const bar = useContext(BarContext);
const baz = useContext(BazContext);

return (
  <span>
    {foo} {bar} {baz}
  </span>
);
```

Much better.

## Advanced Provider Patterns

The example above demonstrates the simplest use-case for context, but often times developers will organize their providers to abstract away a lot of the boilerplate. Exposing your Context object directly can also result in more complex code and even more complex maintenance, as the consuming code is accessing the data directly. By creating wrappers for the `Provider` component and `useContext` hook, you can control exactly what data each component is using, thereby reducing code complexity and simplifying maintenance.

Let us consider a more complex situation: Global styles. take a look at how we might refactor the `ThemeContext` so that it’s wrapped in it’s own custom component:

```
import React, { createContext } from 'react';

const THEMES = {
  blue: { color: '#0000ff', fontSize: '1.25rem' },
  red: { color: '#7ea0ff', fontSize: '2rem' },
};

const ThemeContext = React.createContext();

export default function ThemeProvider({ theme, children }) {
  return (
    <ThemeContext.Provider value={THEMES[theme]}>
      {children}
    </ThemeContext.Provider>
  );
}
```

In the example above, we’ve taken away all of the `ThemeContext` logic and encapsulated it into its own component `ThemeProvider`. This is a very common technique for organizing contexts in a scalable and reusable way.

We can take this a step further by exporting a custom hook `useTheme` from this file, which can then be used by nested components like `Button` to access the theme:

```
import React, { createContext } from 'react';

const THEMES = {
  blue: { color: '#0000ff', fontSize: '1.25rem' },
  red: { color: '#7ea0ff', fontSize: '2rem' },
};

const ThemeContext = React.createContext();

export default function ThemeProvider({ theme, children }) {
  return (
    <ThemeContext.Provider value={THEMES[theme]}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const theme = useContext(ThemeContext);
  return theme;
}
```

Now, we can refactor our `Layout` component to use this new provider. Notice how much cleaner it looks when we abstract away the context logic into its own component (`ThemeProvider`)

```
import React from 'react';
import ThemeProvider from './ThemeProvider';

export default function Layout() {
  return (
    <ThemeProvider theme="blue">
      <Button label="Click Me!" />
    </ThemeProvider>
  );
}
```

We can also refactor the way the `Button` component consumes the theme, by having it use the newly exposed `useTheme` custom hook.

```
import React from 'react';
import { useTheme } from './ThemeProvider';

function Button({ label }) {
  const theme = useTheme();

  return (
    <div style={theme}>
      <button>{label}</button>
    </div>
  );
}
```

## Exercise

Let’s use our context hook knowledge to make our Tic-Tac-Toe use a style theme!

### The problem

✏️ Let’s add in the ability to use a style theme for our app.

- `Game` Component 
    - Create a new piece of state called `theme`, which will store the current theme used by the app (`themes.light` by default).
    - Create a `ThemeContext` object using `React.createContext()`
    - Wrap the component tree in `<ThemeContext.Provider>` and give it a value of the `theme` state.
    - Create and export a custom hook called `useTheme`.
    - (Optional) Add in a button which allows the user to switch between `themes.light` and `themes.dark`
- `Square` Component 
    - Get the theme from the new `useTheme` hook in the `Game` component.

Here’s the starter code

```
const squareStyling = {
  width: '200px',
  height: '200px',
  border: '1px solid black',
  boxSizing: 'border-box',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  fontSize: '6em',
  color: 'black',
};

const boardStyling = {
  display: 'flex',
  flexWrap: 'wrap',
  flexDirection: 'row',
  justifyContent: 'flex-start',
  width: '600px',
  height: '600px',
  boxShadow: '0px 3px 8px 0 rgba(0, 0, 0, 0.1)',
  boxSizing: 'border-box',
};

function boardHasWinner(board) {
  const winningCombos = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  const winningCombo = winningCombos.find((combo) => {
    return (
      board[combo[0]] !== '' &&
      board[combo[0]] === board[combo[1]] &&
      board[combo[0]] === board[combo[2]]
    );
  });
  return !!winningCombo;
}

function Square({ onClick, symbol, id }) {
  const theme = {}; // Get this from a custom hook

  return (
    <div
      id={id}
      style={Object.assign({}, squareStyling, {
        color: theme.text,
        backgroundColor: theme.background,
      })}
      onClick={onClick}
    >
      {symbol}
    </div>
  );
}

function Board({ board, handleSquareClick }) {
  return (
    <div style={boardStyling}>
      {board.map((symbol, index) => (
        <Square
          key={index}
          symbol={symbol}
          onClick={() => handleSquareClick(index)}
        />
      ))}
    </div>
  );
}

// Create a context for your theme
// Provide a theme (light or dark) to the children of this component
// Export a custom hook that returns the current theme
// Consume the custom hook in Square.js
// Create a state and button that allows the user to switch between themes

const blankBoard = ['', '', '', '', '', '', '', '', ''];

function Game() {
  const [board, setBoard] = React.useState(blankBoard);
  const [isXTurn, setIsXTurn] = React.useState(true);

  const currentPlayer = isXTurn ? 'X' : 'O';

  function handleSquareClick(squareIndex) {
    if (!board[squareIndex]) {
      const newBoard = [...board];
      newBoard[squareIndex] = currentPlayer;

      if (boardHasWinner(newBoard)) {
        alert(`${currentPlayer} Wins!`);
        resetGame();
      } else {
        setBoard(newBoard);
        setIsXTurn(!isXTurn);
      }
    }
  }

  function resetGame() {
    setIsXTurn(true);
    setBoard(blankBoard);
  }

  return (
    <>
      <Board board={board} handleSquareClick={handleSquareClick} />
      <button onClick={() => {}}>Toggle Theme</button>
      current player: {currentPlayer}
    </>
  );
}

ReactDOM.render(<Game />, document.getElementById('root'));
```

## Solution

 Click to see the solution

#### Game

```
const squareStyling = {
  width: '200px',
  height: '200px',
  border: '1px solid black',
  boxSizing: 'border-box',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  fontSize: '6em',
  color: 'black',
};

const boardStyling = {
  display: 'flex',
  flexWrap: 'wrap',
  flexDirection: 'row',
  justifyContent: 'flex-start',
  width: '600px',
  height: '600px',
  boxShadow: '0px 3px 8px 0 rgba(0, 0, 0, 0.1)',
  boxSizing: 'border-box',
};

function boardHasWinner(board) {
  const winningCombos = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];

  const winningCombo = winningCombos.find((combo) => {
    return (
      board[combo[0]] !== '' &&
      board[combo[0]] === board[combo[1]] &&
      board[combo[0]] === board[combo[2]]
    );
  });
  return !!winningCombo;
}

const themes = {
  light: {
    text: '#4A5568',
    background: '#EDF2F7',
  },
  dark: {
    text: '#EDF2F7',
    background: '#4A5568',
  },
};
const ThemeContext = React.createContext();

function useTheme() {
  return React.useContext(ThemeContext);
}

function Square({ onClick, symbol, id }) {
  const theme = useTheme();

  return (
    <div
      id={id}
      style={Object.assign({}, squareStyling, {
        color: theme.text,
        backgroundColor: theme.background,
      })}
      onClick={onClick}
    >
      {symbol}
    </div>
  );
}

function Board({ board, handleSquareClick }) {
  return (
    <div style={boardStyling}>
      {board.map((symbol, index) => (
        <Square
          key={index}
          symbol={symbol}
          onClick={() => handleSquareClick(index)}
        />
      ))}
    </div>
  );
}

const blankBoard = ['', '', '', '', '', '', '', '', ''];

function Game() {
  const [board, setBoard] = React.useState(blankBoard);
  const [isXTurn, setIsXTurn] = React.useState(true);
  const [theme, setTheme] = React.useState(themes.light);

  const currentPlayer = isXTurn ? 'X' : 'O';

  function handleSquareClick(squareIndex) {
    if (!board[squareIndex]) {
      const newBoard = [...board];
      newBoard[squareIndex] = currentPlayer;

      if (boardHasWinner(newBoard)) {
        alert(`${currentPlayer} Wins!`);
        resetGame();
      } else {
        setBoard(newBoard);
        setIsXTurn(!isXTurn);
      }
    }
  }

  function handleToggleTheme() {
    setTheme(theme === themes.light ? themes.dark : themes.light);
  }

  function resetGame() {
    setIsXTurn(true);
    setBoard(blankBoard);
  }

  return (
    <ThemeContext.Provider value={theme}>
      <Board board={board} handleSquareClick={handleSquareClick} />
      <button onClick={handleToggleTheme}>Toggle Theme</button>
      current player: {currentPlayer}
    </ThemeContext.Provider>
  );
}

ReactDOM.render(<Game />, document.getElementById('root'));
```

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-react/context-hooks.html",
          "description": "Learn how to manage global app state with context hooks. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```