Here is a list of books generated by components sharing context. (It’s a hydrated component, so try clicking the buttons!)

NOTE: This is how to execute context, but it’s clearly not the best example of when or why to use context! It’s just an implementation of the hook, for the sake of testing out the pattern. Super-long blog post in excrutiating detail re: how to do this is available at “React Context Post”



This is the code for this page (so far!):

---
import BaseLayout from '../layouts/BaseLayout';
import CurrencyApp from '../components/CurrencyApp.jsx';
import { Markdown } from 'astro/components';
---

<BaseLayout title="React currency context">
  <Markdown>
  Here is a list of books generated by React components sharing context:
  </Markdown>
  <hr />
  <CurrencyApp client:load/>
  <hr />
  <Markdown>
  This is the code for this page:
  </Markdown>
</BaseLayout>

Here are the app components:

//Create the file src/components/CurrencyContext.jsx
import { createContext } from 'react';

const CurrencyContext = createContext();

export default CurrencyContext
// src/components/CurrencyApp.jsx
import React from 'react';
import CurrencyContext from '../components/CurrencyContext.jsx';
import Books from "../components/Books.jsx";

//One big object, whose properties are a list, a function, and a currency symbol
const DATA = { 

  list: [
    {
      id: '1',
      title: 'The Road to React',
      price: 19.99,
    },
    {
      id: '2',
      title: 'The Road to GraphQL',
      price: 29.99,
    },
    {
      id: '3',
      title: 'The Road to GastbyJS',
      price: 29.99,
    },
    {
      id: '4',
      title: 'The Rocket to Astro!',
      //title: 'The Voyage to Astro!',
      price: 29.99,
    },
  ],
  
  buy: () => {
    alert("Sorry, this is just a test!");
  },

  currency: "$",
  
};


const CurrencyApp = () => {
  return (
    <CurrencyContext.Provider value={DATA} > //Sharing the entire object via context
        <Books /> 
    </CurrencyContext.Provider>
  );
};

export default CurrencyApp;
// src/components/Books.jsx

import React, { useContext } from 'react';
import CurrencyContext from '../components/CurrencyContext.jsx';
import Book from '../components/Book';

const Books = () => {
  const { list } = useContext(CurrencyContext) // destructure just the list array
  return (
    <ul>
      {list.map((item) => (
        <Book key={item.id} item={item} />
      ))}
    </ul>
  );
};

export default Books
// src/components/Book.jsx

import React, { useContext } from 'react';
import CurrencyContext from '../components/CurrencyContext.jsx';
import BookBuyButton from '../components/BookBuyButton.jsx';

const Book = ({ item }) => {
  const { currency } = useContext(CurrencyContext); //destructure just the currency symbol

  return (
    <li style={{lineHeight: "1.85em"}}>
      <BookBuyButton /> &nbsp; &nbsp; {item.title} - {item.price} {currency}
    </li>
  );
};

export default Book

And now, a new component, a Buy button, that will execute our buy function when clicked. (JavaScript! Yay!) This is the component that will require us to hydrate our CurrencyApp on the Astro page.

// src/componenst/BuyBookButton.jsx

import React, { useContext } from "react";

import CurrencyContext from "../components/CurrencyContext.jsx";

const BookBuyButton = () => {
  const { buy } = useContext(CurrencyContext); //destructure just the buy function
  return (
      <button onClick={buy}>Buy!</button>
  );
};

export default BookBuyButton;