Skip to content

Instantly share code, notes, and snippets.

@lovetingyuan
Last active December 25, 2020 09:49
Show Gist options
  • Save lovetingyuan/26e9b65ff5a6f83c8893b8d1cf154a68 to your computer and use it in GitHub Desktop.
Save lovetingyuan/26e9b65ff5a6f83c8893b8d1cf154a68 to your computer and use it in GitHub Desktop.
simple unstated next, useContext to manage state
import React from 'react'
interface ContainerProviderProps<State = void> {
initialState?: State
children: React.ReactNode
}
const usecontext = React.useContext
export default function createContainer<Value, State = void>(
usehook: (initialState?: State) => Value,
) {
const Context = React.createContext<Value | null>(null)
function Container(props: ContainerProviderProps<State>): JSX.Element
function Container(): Value
function Container(props?: ContainerProviderProps<State>): Value | JSX.Element {
if (props) {
const value = usehook(props.initialState)
return React.createElement(Context.Provider, { value }, props.children)
}
const value = usecontext(Context)
if (value === null) {
throw new Error('Component must be wrapped with container component returned by `createContainer`.')
}
return value
}
if (usehook.name) {
Object.defineProperty(Container, 'name', {
value: usehook.name,
configurable: true
})
}
return Container
}
@lovetingyuan
Copy link
Author

lovetingyuan commented Dec 23, 2020

import React, { useState } from "react"
import createContainer from "./simple-unstated-next.js"

function useCounter(initialState = 0) {
  let [count, setCount] = useState(initialState)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

const Counter = createContainer(useCounter)

function CounterDisplay() {
  const { decrement, count, increment } = Counter()
  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  )
}

export default function App() {
  return (
    <Counter>
      <CounterDisplay />
      <Counter initialState={2}>
        <div>
          <div>
            <CounterDisplay />
          </div>
        </div>
      </Counter>
    </Counter>
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment