richytong / arche

HTML as JavaScript
MIT License
6 stars 2 forks source link

useContext Hook Support #4

Open toshvelaga opened 3 years ago

toshvelaga commented 3 years ago

Hey there I was wondering if Arche had built in support for the useContext hook? I tried to replicate this jsfiddle using Arche but was having some trouble. I included my code below which is most of the code in the jsfiddle with Arche.

Here is also a quick explanation of the useContext hook if needed.

const { useState, useEffect, useReducer, createContext, useContext } = React
const ReactElement = Arche(React)
const {
  A, P, B, Q, I, Ul, Ol, Li,
  H1, H2, H3, H4, H5, H6, Hr, Br,
  Script, Html, Body, Nav, Section, Footer, Span, Div, Img, Video,
  Form, Fieldset, Input, Label, Textarea, Select, Option,
  Button, Iframe, Blockquote, Code, Pre,
} = ReactElement

const themes = ['light', 'dark', 'pink']

// error: not a function
const ThemeContext = React.createContext({
  theme: themes[0],
  changeTheme: () => {},
})

const ThemeSwitcher = () => {
  const { theme, changeTheme } = React.useContext(ThemeContext)

  const handleThemeChange = (e) => {
    changeTheme(e.target.value)
  }

  return Div({ class: 'themeSwitcher', id: '' }, [
    P('Select theme:'),
    Select(
      {
        value: theme,
        onChange(e) {
          handleThemeChange(e)
        },
      },
      [
        themes.map((themeOption) => {
          return Option({ value: themeOption, key: themeOption }, themeOption)
        }),
      ]
    ),
  ])
}

const Article = () => {
  const { theme } = React.useContext(ThemeContext)

  return Div({ class: `article ${theme}`, id: '' }, [
    H2({ class: '', id: '' }, 'Fun facts about sloths'),
    P(`Sloths are tropical mammals that live in Central and South America.`),
    P(`There are six species of sloth`),
  ])
}

// how do I do ThemeContext.Provider?
const ArticleWrapper = () => {
  const [theme, setTheme] = React.useState(themes[0])

  return ThemeContext({}, [ThemeSwitcher(), Article()])
}

export default ArticleWrapper
richytong commented 3 years ago

Hello, I believe you can use the ThemeContext.Provider directly as a function.

const ArticleWrapper = () => {
  const [theme, setTheme] = React.useState(themes[0])

  return ThemeContext.Provider({
    value: { theme, changeTheme: setTheme },
  }, [ThemeSwitcher(), Article()])
}
toshvelaga commented 3 years ago

Hey thank you for this! I tired your suggestion and got this error:

Screen Shot 2021-06-20 at 1 24 45 PM
richytong commented 3 years ago

My mistake, please see below for an updated example demonstrating correct usage of React.createContext and the useContext hook. To use a React Context with Arche, simply wrap the context's Provider with ReactElement and supply value as a prop, specifying children in the next argument. Also make sure to wrap your React components with ReactElement - this is different than regular jsx.

const { useState, useEffect, useReducer, createContext, useContext } = React
const ReactElement = Arche(React)
const {
  A, P, B, Q, I, Ul, Ol, Li,
  H1, H2, H3, H4, H5, H6, Hr, Br,
  Script, Html, Body, Nav, Section, Footer, Span, Div, Img, Video,
  Form, Fieldset, Input, Label, Textarea, Select, Option,
  Button, Iframe, Blockquote, Code, Pre,
} = ReactElement

const themes = ['light', 'dark', 'pink']

// error: not a function
const ThemeContext = React.createContext({
  theme: themes[0],
  changeTheme: () => {},
})

const ThemeSwitcher = ReactElement(() => {
  const { theme, changeTheme } = React.useContext(ThemeContext)

  const handleThemeChange = (e) => {
    changeTheme(e.target.value)
  }

  return Div({ class: 'themeSwitcher', id: '' }, [
    P('Select theme:'),
    Select(
      {
        value: theme,
        onChange(e) {
          handleThemeChange(e)
        },
      },
      [
        themes.map((themeOption) => {
          return Option({ value: themeOption, key: themeOption }, themeOption)
        }),
      ]
    ),
  ])
})

const Article = ReactElement(() => {
  const { theme } = React.useContext(ThemeContext)

  return Div({ class: `article ${theme}`, id: '' }, [
    H2({ class: '', id: '' }, 'Fun facts about sloths'),
    P(`Sloths are tropical mammals that live in Central and South America.`),
    P(`There are six species of sloth`),
  ])
})

const ArticleWrapper = ReactElement(() => {
  const [theme, setTheme] = React.useState(themes[0])

  return ReactElement(ThemeContext.Provider)({
    value: { theme, changeTheme: setTheme },
  }, [ThemeSwitcher(), Article()])
})

export default ArticleWrapper
toshvelaga commented 3 years ago

Ok very cool! Thank you for providing this. This code works perfectly for me. It's good to know that I can use useContext with Arche for my future projects.