---
# System prepended metadata

title: '[React] Custom Context Provider (Context API)'
tags: [react]

---

# [React] Custom Context Provider (Context API)

###### tags: `react`

## What is React's context | React context是什麼
> Context provides a way to pass data through the component tree without having to pass props down manually at every level.

By [React](https://zh-hant.reactjs.org/docs/context.html)

Context 是一種用來傳遞資料的方式，讓我們不需要使用Props一層一層傳遞

在開始使用前我們要先建立這些相當於整個網頁app的全域變數，並做成一個Provider以供其他component使用

```
import { createContext } from 'react'

const Context = createContext();
```

稍後我們建立這個Provider時會將將這個Context當成一個Component回傳，並且將這些變數包在value props當中，這些變數始得被使用。

根據React官方文件的寫法如下

```
<Context.Provider value = {/* some value */} >
```

若覺得在Component當中加入 .Provider 較不直覺，亦可在宣告時處理

```
import { createContext } from 'react'

const Context = createContext();
ContextProvider = Context.Provider

// 稍後會使用的回傳值則會變成ContextProvider
<ContextProvider value = {/* some value */} >
```

## Provider當中的變數宣告與使用


### 定義Provider
在這裡將Provider命名為StateProvider，並將Props.children傳入，故它可以把整個網頁app包起來
```
// state.js

function StateProvider( {children} ){
    const id = 10;
    
    return (<ContextProvider value = {{id}} >
                { children }
            </ContextProvider>
    );
}

```

### 定義Consumer
將consumer寫成一個hook，以便在其他的component當中輕易的使用
前面在做Provider時使用了```createContext()```
而現在要使用(Consume)，則會使用```useContext()```

```
// state.js

import { useContext } from 'react'

function useId(){
    return useContext(Context)
}
```

### 使用
先將整個app用這個Provider包起來
```
// _app.js

import { ContextProvider } from '/path/to/state.js'

function MyApp({ Component, pageProps }) {
  return (
      <ContextProvider>
        <Page>
          <Component {...pageProps} />
        </Page>
      </ContextProvider>
  );
}

```
而在要使用的頁面(page)或component當中
```
// index.js

import { useId } from '/path/to/state.js'

export default function Index(){
    const { id } = useId()
    
    return (
        <div> {id} </div>
    )

}
```

##  Example 範例 : Shopping Cart's State 購物車的狀態(開啟open/關閉close)
### 搭配State Hook ```useState()```

#### cartState.js
```
// cartState.js

import { createContext, useContext, useState } from 'react';

const LocalStateContext = createContext();
const LocalStateProvider = LocalStateContext.Provider;

function CartStateProvider({ children }) {
  const [cartOpen, setCartOpen] = useState(false);

  function toggleCart() {
    setCartOpen(!cartOpen);
  }

  function closeCart() {
    setCartOpen(false);
  }

  function openCart() {
    setCartOpen(true);
  }

  return (
    <LocalStateProvider
      value={{ cartOpen, setCartOpen, toggleCart, closeCart, openCart }}
    >
      {children}
    </LocalStateProvider>
  );
}

function useCart() {
  const all = useContext(LocalStateContext);
  return all;
}

export { CartStateProvider, useCart };
```
#### _app.js
```
// _app.js

import { CartStateProvider } from '../lib/cartState';

function MyApp({ Component, pageProps }) {
  return (
      <CartStateProvider>
        <Page>
          <Component {...pageProps} />
        </Page>
      </CartStateProvider>
  );
}
```

#### Cart.js
```
// Cart.js

import { useCart } from '../lib/cartState';

export default function Cart(){
  const { cartOpen, closeCart } = useCart();
  return (
    <div open={cartOpen}>
      <header>
        <h2>Cart</h2>
        <button type="button" onClick={closeCart}>
          &times;
        </button>
      </header>
    </div>
  );
}
