ezcon
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

ezcon ( react easy context )

  • You can declare useState(ezState) and useRef(ezRef) globally, use Provider to specify the scope of the hook.
  • It's based on the default react context.
  • type inferred based on the useState and useRef.
  • You can use scope providers.
  • If the same Provider is nested and used, an Error is thrown.
  • You can use combination of Providers.

NPM JavaScript Style Guide

Install

npm install --save ezcon

Usage 1 : ezState

import { ezState } from 'ezcon'

const ezState1 = ezState(0)

export function App() {
  return (
    <ezState1.Provider>
      <ScopeTest1 />
      <ScopeTest2 />
    </ezState1.Provider>
  )
}

function ScopeTest1() {
  const value1 = ezState1.useValue()
  console.log('ScopeTest1 call', value1)
  return <div />
}

function ScopeTest2() {
  const dispatch1 = ezState1.useDispatch()
  console.log('ScopeTest2 call')
  return <button onClick={() => dispatch1((p) => p + 1)} />
}

Click the button in ScopeTest2 four times.

ScopeTest1 call 1
ScopeTest1 call 2
ScopeTest1 call 3
ScopeTest1 call 4

Usage 2 : ezCombineProvider()

import { ezState, ezRef, ezCombineProvider } from 'ezcon'

export const ezTest = {
  state1: ezState(0),
  state2: ezState(() => 0),
  state3: ezState(() => 0),
  ref1: ezRef(0)
} as const

export const ScopeTestProvider = ezCombineProvider(
  [ezTest.state1, ezTest.state2, ezTest.state3, ezTest.ref1],
  () => console.log('hello ezcon Provider hook')
)

export function App() {
  return (
    <>
      <ScopeTestProvider>
        <ScopeTest1 />
        <ScopeTest2 />
      </ScopeTestProvider>
      <OutsideScope />
    </>
  )
}
function ScopeTest1() {
  const value1 = ezTest.state1.useValue()
  const value2 = ezTest.state2.useValue()
  const value3 = ezTest.state3.useValue()
  const refObj1 = ezTest.ref1.useMutableRefObject()
  console.log('ScopeTest1 call', value1, value2, value3, refObj1.current)
  return <div />
}
function ScopeTest2() {
  // const value1 = ezTest.state1.useValue()
  const value2 = ezTest.state2.useValue()
  const value3 = ezTest.state3.useValue()
  const refObj1 = ezTest.ref1.useMutableRefObject()

  const dispatch1 = ezTest.state1.useDispatch()
  console.log('ScopeTest2 call')
  return <button onClick={() => dispatch1((p) => p + 1)} />
}
function OutsideScope() {
  const value1 = ezTest.state1.useValue()
  const value2 = ezTest.state2.useValue()
  const value3 = ezTest.state3.useValue()
  const refObj1 = ezTest.ref1.useMutableRefObject()
  console.log('OutsideScope call')
  return <div />
}

Click the button in ScopeTest2 four times.

hello ezcon Provider hook
ScopeTest1 call 1 0 0 0
ScopeTest1 call 2 0 0 0
ScopeTest1 call 3 0 0 0
ScopeTest1 call 4 0 0 0

My migration Example 1

before

export const ctxModal = {
  node: createContext<ReactNode>(null),
  setNode: createContext<Dispatch<SetStateAction<ReactNode>>>(() => {})
} as const

export const ProviderModal = (props: { children: ReactNode }) => {
  const [node, setNode] = useState<ReactNode>(null)
  return (
    <ctxModal.setNode.Provider value={setNode}>
      <ctxModal.node.Provider value={node}>
        {props.children}
      </ctxModal.node.Provider>
    </ctxModal.setNode.Provider>
  )
}
<ProviderModal>{props.children}</ProviderModal>
const setNode = useContext(ctxModal.setNode)
const node = useContext(ctxModal.node)

after

export const ezModal = ezState<ReactNode>(null)
<ezModal.Provider>{props.children}</ezModal.Provider>
const setNode = ezModal.useDispatch()
const node = ezModal.useValue()

My migration Example 2 ezCombineProvider

before

export const ctxPBL = {
  summaryArr: createContext<nsPageBoard.Summary[]>([]),
  pageItemArr: createContext<nsPageBoard.PageItem[]>([]),
  refetch: createContext(() => {}),
} as const;

export const ProviderPBL = (props: { children: ReactNode }) => {
  // ...
  useEffect(() => {
    // ...
  }, [...]);

  const q = useQueryGet(...);
  const summaryArr: nsPageBoard.Summary[] = q.data?.summaryArr ?? [];
  const pageItemArr: nsPageBoard.PageItem[] = q.data?.pageItemArr ?? [];
  return (
    <ctxPBL.summaryArr.Provider value={summaryArr}>
      <ctxPBL.pageItemArr.Provider value={pageItemArr}>
        <ctxPBL.refetch.Provider value={useCallback(() => q.refetch(), [q])}>
          {props.children}
        </ctxPBL.refetch.Provider>
      </ctxPBL.pageItemArr.Provider>
    </ctxPBL.summaryArr.Provider>
  );
};
const pageItemArr = useContext(ctxPBL.pageItemArr)
const summaryArr = useContext(ctxPBL.summaryArr)
const pblRefetch = useContext(ctxPBL.refetch)

after

export const ezPBL = {
  summaryArr: ezState<nsPageBoard.Summary[]>([]),
  pageItemArr: ezState<nsPageBoard.PageItem[]>([]),
  refetch: ezRef(() => {}),
} as const;


// ezCombineProvider
export const ProviderPBL = ezCombineProvider(
  [ezPBL.summaryArr, ezPBL.pageItemArr, ezPBL.refetch],
  // Hook to run when the provider is registered.
  () => {
    // ...
    useEffect(() => {
      // ...
    }, [...]);

    const q = useQueryGet(...);

    // ezState
    const dispatchSummaryArr = ezPBL.summaryArr.useDispatch();
    const disPatchPageItemArr = ezPBL.pageItemArr.useDispatch();
    useEffect(() => {
      if (q.data) {
        dispatchSummaryArr(q.data.summaryArr ?? []);
        disPatchPageItemArr(q.data.pageItemArr ?? []);
      }
    }, [q.data, disPatchPageItemArr, dispatchSummaryArr]);

    // ezRef
    ezPBL.refetch.useMutableRefObject().current = q.refetch;

);
const summaryArr = ezPBL.summaryArr.useValue()
const pageItemArr = ezPBL.pageItemArr.useValue()
const refetchPBL = ezPBL.refetch.useMutableRefObject().current

My migration Example 3 useState

after

export const ezMyTheme = {
  theme: ezState<MyTheme>(factoryMyTheme(null)),
  toggle: ezRef<() => void>(() => {})
} as const

export const ProviderMyTheme = ezCombineProvider(
  [ezMyTheme.theme, ezMyTheme.toggle],
  () => {
    const [myThemeMode, setMyThemeMode] = useState<MyThemeMode>(null) // useState

    ezMyTheme.toggle.useMutableRefObject().current = () => {
      setMyThemeMode((p) =>
        p === null || p === 'light mode' ? 'dark mode' : 'light mode'
      )
    }

    const dispatchMyTheme = ezMyTheme.theme.useDispatch()
    useEffect(() => {
      if (myThemeMode === null) {
        const value = localStorage.getItem(MyLsKey.myThemeMode)
        switch (value) {
          case 'dark mode':
            setMyThemeMode('dark mode')
            break
          case 'light mode':
          default:
            setMyThemeMode('light mode')
            break
        }
      } else {
        localStorage.setItem(MyLsKey.myThemeMode, myThemeMode)
        dispatchMyTheme(factoryMyTheme(myThemeMode))
      }
    }, [myThemeMode, dispatchMyTheme])
  }
)

License

MIT © eezz4

Package Sidebar

Install

npm i ezcon

Weekly Downloads

0

Version

1.0.2

License

MIT

Unpacked Size

27 kB

Total Files

7

Last publish

Collaborators

  • eezz4