store.tsx 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import {
  2. createContext,
  3. useContext,
  4. useRef,
  5. } from 'react'
  6. import {
  7. create,
  8. useStore as useZustandStore,
  9. } from 'zustand'
  10. import type {
  11. FileEntity,
  12. } from './types'
  13. type Shape = {
  14. files: FileEntity[]
  15. setFiles: (files: FileEntity[]) => void
  16. }
  17. export const createFileStore = (
  18. value: FileEntity[] = [],
  19. onChange?: (files: FileEntity[]) => void,
  20. ) => {
  21. return create<Shape>(set => ({
  22. files: [...value],
  23. setFiles: (files) => {
  24. set({ files })
  25. onChange?.(files)
  26. },
  27. }))
  28. }
  29. type FileStore = ReturnType<typeof createFileStore>
  30. export const FileContext = createContext<FileStore | null>(null)
  31. export function useStore<T>(selector: (state: Shape) => T): T {
  32. const store = useContext(FileContext)
  33. if (!store)
  34. throw new Error('Missing FileContext.Provider in the tree')
  35. return useZustandStore(store, selector)
  36. }
  37. export const useFileStore = () => {
  38. return useContext(FileContext)!
  39. }
  40. type FileProviderProps = {
  41. children: React.ReactNode
  42. value?: FileEntity[]
  43. onChange?: (files: FileEntity[]) => void
  44. }
  45. export const FileContextProvider = ({
  46. children,
  47. value,
  48. onChange,
  49. }: FileProviderProps) => {
  50. const storeRef = useRef<FileStore>()
  51. if (!storeRef.current)
  52. storeRef.current = createFileStore(value, onChange)
  53. return (
  54. <FileContext.Provider value={storeRef.current}>
  55. {children}
  56. </FileContext.Provider>
  57. )
  58. }