Skip to content

Commit

Permalink
feat(zustand 3): bumped zustand to 3, adjusted peerDependencies to re…
Browse files Browse the repository at this point in the history
…quire zustand 3, adjusted deprecated api access, cleanup

BREAKING CHANGE: Requires zustand 3
  • Loading branch information
BowlingX committed Feb 4, 2021
1 parent dad0927 commit c51a92c
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 71 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"immer": ">=7",
"react": ">=16.8",
"react-dom": ">=16.8",
"zustand": "^2"
"zustand": "^3"
},
"devDependencies": {
"@babel/core": "^7.7.4",
Expand Down Expand Up @@ -104,7 +104,7 @@
"tslint-immutable": "^6.0.1",
"typedoc": "^0.15.4",
"typescript": "^4.1.3",
"zustand": "^2.2.3"
"zustand": "^3.3.1"
},
"resolutions": {
"lodash": "4.17.19",
Expand Down
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export {
export { StoreState } from './lib/middleware'
export {
HistoryManagement,
geschichte,
useGeschichte,
factoryParameters,
useBatchQuery,
useStore,
Expand Down
9 changes: 4 additions & 5 deletions src/lib/adapters/History.js.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { StoreApi, UseStore } from 'zustand'
// tslint:disable-next-line:no-submodule-imports
import shallow from 'zustand/shallow'
import { StoreState } from '../middleware'
import { geschichte, HistoryManagement, StoreContext } from '../store'
import { HistoryManagement, StoreContext, useGeschichte } from '../store'

export interface Props {
/** a history instance (e.g. createBrowserHistory()) */
Expand Down Expand Up @@ -44,11 +44,10 @@ export const GeschichteWithHistory = forwardRef<Refs, Props>(
}
}, [history])

const value = useMemo(() => geschichte(historyInstance), [
const value = useMemo(() => useGeschichte(historyInstance), [
historyInstance
]) as [UseStore<StoreState<any>>, StoreApi<StoreState<any>>]
const [useStore] = value
const state = useStore(
])
const state = value(
({ unregister, updateFromQuery }: StoreState<any>) => ({
unregister,
updateFromQuery
Expand Down
12 changes: 6 additions & 6 deletions src/lib/adapters/Next.js.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* tslint:disable:no-expression-statement readonly-array */
import React, { FC, useEffect, useMemo } from 'react'
import { StoreApi, UseStore } from 'zustand'
// tslint:disable-next-line:no-submodule-imports
import shallow from 'zustand/shallow'
import { StoreState } from '../middleware'
import { geschichte, HistoryManagement, StoreContext } from '../store'
import { HistoryManagement, StoreContext, useGeschichte } from '../store'

const split = (url: string) => url.split('?')

Expand Down Expand Up @@ -42,10 +41,9 @@ const GeschichteForNextjs: FC<Props> = ({ children, asPath, Router }) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

const value = useMemo(() => geschichte(historyInstance), [
const useStore = useMemo(() => useGeschichte(historyInstance), [
historyInstance
]) as [UseStore<StoreState<any>>, StoreApi<StoreState<any>>]
const [useStore] = value
])
const state = useStore(
// tslint:disable-next-line:no-shadowed-variable
({ unregister, updateFromQuery }: StoreState<any>) => ({
Expand All @@ -68,7 +66,9 @@ const GeschichteForNextjs: FC<Props> = ({ children, asPath, Router }) => {
return unregister()
}
}, [state])
return <StoreContext.Provider value={value}>{children}</StoreContext.Provider>
return (
<StoreContext.Provider value={useStore}>{children}</StoreContext.Provider>
)
}

export default GeschichteForNextjs
63 changes: 33 additions & 30 deletions src/lib/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface GenericObject {
[key: string]: any
}

export interface NamespaceValues<ValueState> {
export interface NamespaceValues<ValueState extends State> {
/** the amount of elements currently subscribed to the namespaces values */
subscribers: number
values: ValueState
Expand All @@ -39,24 +39,24 @@ export type ReplaceStateFunction<T> = (
valueCreator: (state: T) => void
) => void

export interface InnerNamespace<T> {
export interface InnerNamespace<T extends State> {
[ns: string]: NamespaceValues<T>
}
export interface StoreState<ValueState = object> {
updateFromQuery: (query: string) => void
batchReplaceState: (
export interface StoreState<ValueState extends State> extends State {
readonly updateFromQuery: (query: string) => void
readonly batchReplaceState: (
ns: readonly string[],
fn: (...valueState: ValueState[]) => void
) => void
batchPushState: (
readonly batchPushState: (
ns: readonly string[],
fn: (...valueState: ValueState[]) => void
) => void
namespaces: InnerNamespace<ValueState>
pushState: PushStateFunction<ValueState>
replaceState: ReplaceStateFunction<ValueState>
readonly pushState: PushStateFunction<ValueState>
readonly replaceState: ReplaceStateFunction<ValueState>
/** registers a new namespace */
register: (
readonly register: (
config: Config,
mappedConfig: MappedConfig,
ns: string,
Expand All @@ -65,29 +65,31 @@ export interface StoreState<ValueState = object> {
values: ValueState
) => () => void
/** will delete all namespaces and remove the history listener */
unregister: () => void
resetPush: (ns: string) => void
resetReplace: (ns: string) => void
initialQueries: () => object
readonly unregister: () => void
readonly resetPush: (ns: string) => void
readonly resetReplace: (ns: string) => void
readonly initialQueries: () => object
}

type NamespaceProducerFunction<T> = (state: NamespaceValues<T>) => void
type InnerNamespaceProducerFunction<T> = (
type NamespaceProducerFunction<T extends State> = (
state: NamespaceValues<T>
) => void
type InnerNamespaceProducerFunction<T extends State> = (
state: InnerNamespace<T>
) => InnerNamespace<T> | void

export type NamespaceProducer<T> = (
export type NamespaceProducer<T extends State> = (
stateProducer: NamespaceProducerFunction<T>,
eventType: HistoryEventType,
ns?: string
) => void
export type GenericConverter<T> = (
export type GenericConverter<T extends State> = (
stateProducer: InnerNamespaceProducerFunction<T>,
eventType: HistoryEventType,
ns?: string
) => void

export type ImmerProducer<T> = (
export type ImmerProducer<T extends State> = (
stateMapper: (changes: Patch[], values: StoreState<T>) => StoreState<T>,
fn: NamespaceProducerFunction<T> & InnerNamespaceProducerFunction<T>,
eventType: HistoryEventType,
Expand All @@ -100,9 +102,9 @@ export declare type StateCreator<T extends State> = (
api: StoreApi<StoreState<T>>
) => StoreState<T>

export const historyManagement = <T>(historyInstance: HistoryManagement) => (
apply: StateCreator<T>
) => (
export const historyManagement = <T extends State>(
historyInstance: HistoryManagement
) => (apply: StateCreator<T>) => (
set: ImmerProducer<T>,
get: GetState<StoreState<T>>,
api: StoreApi<StoreState<T>>
Expand Down Expand Up @@ -210,7 +212,7 @@ export const historyManagement = <T>(historyInstance: HistoryManagement) => (
* If a namespace is given, will forward the mutation instead of updating
* the whole state. Initializes the namespace if it does not exist yet
*/
const namespaceProducer = <T>(
const namespaceProducer = <T extends State>(
fn: NamespaceProducerFunction<T> & InnerNamespaceProducerFunction<T>,
ns?: string
) => (state: StoreState<T>) => {
Expand All @@ -231,30 +233,31 @@ const namespaceProducer = <T>(
state.namespaces[ns] = next as NamespaceValues<T>
}

export declare type ImmerStateCreator<T extends State> = (
export type ImmerStateCreator<T extends State> = (
fn: ImmerProducer<T>,
get: GetState<StoreState<T>>,
api: StoreApi<StoreState<T>>
) => StoreState<T>

export declare type SetImmerState<T> = (
export type SetImmerState<T> = (
stateProducer: (state: T) => T,
debugMiddlewareKey: string
) => void

export const immerWithPatches = <T>(config: ImmerStateCreator<T>) => (
export const immerWithPatches = <T extends State>(
config: ImmerStateCreator<T>
) => (
set: SetImmerState<StoreState<T>>,
get: GetState<StoreState<T>>,
api: StoreApi<StoreState<T>>
) =>
config(
(valueMapper, fn, type: HistoryEventType, ns?: string) => {
return set((currentState: StoreState<T>) => {
return set(currentState => {
const [nextValues, changes] = produceWithPatches(
namespaceProducer(fn, ns)
// @ts-ignore
// FIXME: Need to check why this causes an error
)(currentState)
// FIXME: Not sure why this is not working properly with the types
)(currentState as any)
return valueMapper(changes, nextValues as StoreState<T>)
}, `action_${HistoryEventType[type]}`)
},
Expand All @@ -264,7 +267,7 @@ export const immerWithPatches = <T>(config: ImmerStateCreator<T>) => (

const parseSearchString = (search: string) => parse(search)

export const converter = <T extends GenericObject>(
export const converter = <T extends State>(
historyInstance: HistoryManagement
) => (
set: NamespaceProducer<T> & GenericConverter<T>,
Expand Down
42 changes: 19 additions & 23 deletions src/lib/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
useMemo,
useState
} from 'react'
import { create, StateCreator, StoreApi, UseStore } from 'zustand'
import create, { State, StateCreator, UseStore } from 'zustand'
// tslint:disable-next-line:no-submodule-imports
import shallow from 'zustand/shallow'
import {
Expand All @@ -29,10 +29,9 @@ import {
enablePatches()

export const DEFAULT_NAMESPACE = 'default'

export const StoreContext = createContext<
[UseStore<StoreState<any>>, StoreApi<StoreState<any>>] | null
>(null)
export const StoreContext = createContext<UseStore<StoreState<State>> | null>(
null
)

export interface Parameter {
readonly name: string
Expand All @@ -59,7 +58,9 @@ export interface HistoryManagement {
readonly replace: (next: string) => void
}

export const geschichte = <T = object>(historyInstance: HistoryManagement) => {
export const useGeschichte = <T extends State>(
historyInstance: HistoryManagement
) => {
const thisStore = converter<T>(historyInstance)
const storeWithHistory = historyManagement<T>(historyInstance)(thisStore)

Expand All @@ -69,22 +70,20 @@ export const geschichte = <T = object>(historyInstance: HistoryManagement) => {
if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
// tslint:disable-next-line:no-submodule-imports
const { devtools } = require('zustand/middleware')
return create(devtools(middleware, 'geschichte'))
return create(devtools(middleware, 'geschichte')) as UseStore<
StoreState<State>
>
}
return create(middleware)
}

type InitialValuesProvider<T = object> = T | (() => T)
type InitialValuesProvider<T extends State> = T | (() => T)

export const useStore = <T = any>() => {
const [store] = useContext(StoreContext) as [
UseStore<StoreState<T>>,
StoreApi<StoreState<T>>
]
return store
export const useStore = <T extends State>() => {
return useContext(StoreContext) as UseStore<StoreState<T>>
}

export const useBatchQuery = <T = any>() => {
export const useBatchQuery = <T extends State>() => {
const store = useStore<T>()
return store(
({ batchPushState, batchReplaceState }) => ({
Expand All @@ -95,7 +94,7 @@ export const useBatchQuery = <T = any>() => {
)
}

export const factoryParameters = <T = {}>(
export const factoryParameters = <T extends State>(
config: Config,
// tslint:disable-next-line:no-object-literal-type-assertion
defaultInitialValues: InitialValuesProvider<T> = {} as T,
Expand Down Expand Up @@ -133,10 +132,7 @@ export const factoryParameters = <T = {}>(
const memInitBlank = memoizeOne(initBlank)

const useQuery = () => {
const [useStore, api] = useContext(StoreContext) as [
UseStore<StoreState<T>>,
StoreApi<StoreState<T>>
]
const useStore = useContext(StoreContext) as UseStore<StoreState<T>>

const {
register,
Expand Down Expand Up @@ -165,7 +161,7 @@ export const factoryParameters = <T = {}>(
)

const initialRegisterState = useMemo(() => {
const namespaceData = api.getState().namespaces[ns] || {}
const namespaceData = useStore.getState().namespaces[ns] || {}
const { values, query, initialValues } = namespaceData
if (values) {
return {
Expand All @@ -175,7 +171,7 @@ export const factoryParameters = <T = {}>(
}
}
return memInitBlank(initialQueries())
}, [api])
}, [useStore])

const [currentState, setCurrentState] = useState({
initialValues: initialRegisterState.initialValues,
Expand All @@ -192,7 +188,7 @@ export const factoryParameters = <T = {}>(
initialRegisterState.values
)

const unsubscribe = api.subscribe<{
const unsubscribe = useStore.subscribe<{
readonly values: T
readonly initialValues: T
}>(
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16294,10 +16294,10 @@ yargs@~3.10.0:
decamelize "^1.0.0"
window-size "0.1.0"

zustand@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-2.2.3.tgz#07ee668bf600a5e0dcff8f8b60f35faa149f65d5"
integrity sha512-SSd5DzbwUN0b8ePW4I+8mSdXQc6UOqTgYzlMtoNvf7pogmFoXjeE0wZwCVopoZBnzz/uRBD2dsozzM2FXDQcXw==
zustand@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.3.1.tgz#de5c4b51112b84e0f819d8b3f336fbfbc087d758"
integrity sha512-o0rgrBsi29nCkPHdhtkAHisCIlmRUoXOV+1AmDMeCgkGG0i5edFSpGU0KiZYBvFmBYycnck4Z07JsLYDjSET9g==

zwitch@^1.0.0:
version "1.0.5"
Expand Down

0 comments on commit c51a92c

Please sign in to comment.