diff --git a/package.json b/package.json index b0776cb..9a87bf0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "suspense-service", - "version": "0.2.6", + "version": "0.2.7", "description": "Suspense integration library for React", "repository": "github:patrickroberts/suspense-service", "main": "dst/cjs/suspense-service.js", diff --git a/src/Service/Consumer/index.tsx b/src/Service/Consumer/index.tsx index 69b8198..9516b53 100644 --- a/src/Service/Consumer/index.tsx +++ b/src/Service/Consumer/index.tsx @@ -15,8 +15,10 @@ export function createServiceConsumer( ): ServiceConsumer { const ResourceConsumer: ServiceConsumer = ({ id, children }) => { const render = useCallback(( - [resource, setState]: [Resource, Dispatch>], + resourceAndSetState: [Resource, Dispatch>], ) => { + const resource = resourceAndSetState[0]; + const setState = resourceAndSetState[1]; const response = resource(); return children(response, setState); diff --git a/src/Service/Provider/index.tsx b/src/Service/Provider/index.tsx index 4eef62d..13e7914 100644 --- a/src/Service/Provider/index.tsx +++ b/src/Service/Provider/index.tsx @@ -1,4 +1,4 @@ -import React, { ComponentType, Dispatch, SetStateAction, Suspense, isValidElement, memo, useMemo } from 'react'; +import React, { ComponentType, Dispatch, SetStateAction, Suspense, memo, useMemo } from 'react'; import Id from '../../IdContext/Id'; import IdContext from '../../IdContext'; import useResetState from '../../State/useResetState'; @@ -18,10 +18,12 @@ export function createServiceProvider( const ResourceProvider: ServiceProvider = ({ request, id, children, fallback, reset, }) => { - const [state, setState] = useResetState(request, reset); + const stateAndSetState = useResetState(request, reset); + const state = stateAndSetState[0]; + const setState = stateAndSetState[1]; const resource = useHandler(state, id); const element = useMemo(() => ( - isValidElement(fallback) + fallback != null ? {children} : children ), [children, fallback]); diff --git a/src/Service/index.ts b/src/Service/index.ts index 9807969..45ddaaf 100644 --- a/src/Service/index.ts +++ b/src/Service/index.ts @@ -53,7 +53,9 @@ export function createService( export function useServiceState( service: Service, id: Id = null, ): [TResponse, Dispatch>] { - const [resource, setState] = useIdContext(service[kResource], id); + const resourceAndSetState = useIdContext(service[kResource], id); + const resource = resourceAndSetState[0]; + const setState = resourceAndSetState[1]; const response = resource(); return [response, setState]; @@ -65,7 +67,5 @@ export function useServiceState( * @param id the {@link ServiceProviderProps.id | ServiceProvider id} to use */ export function useService(service: Service, id: Id = null): TResponse { - const [response] = useServiceState(service, id); - - return response; + return useServiceState(service, id)[0]; } diff --git a/src/State/is.ts b/src/State/is.ts deleted file mode 100644 index 16100f8..0000000 --- a/src/State/is.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { DependencyList } from 'react'; - -/** @ignore */ -export default function is(a: DependencyList | undefined, b: DependencyList | undefined): boolean { - if (!a || !b || a.length !== b.length) return false; - - for (let i = 0; i < a.length; ++i) { - if (!Object.is(a[i], b[i])) return false; - } - - return true; -} diff --git a/src/State/useForceUpdate.ts b/src/State/useForceUpdate.ts index da6ddb5..bdfa203 100644 --- a/src/State/useForceUpdate.ts +++ b/src/State/useForceUpdate.ts @@ -2,6 +2,5 @@ import { DispatchWithoutAction, useReducer } from 'react'; /** @ignore */ export default function useForceUpdate(): DispatchWithoutAction { - const [, dispatch] = useReducer(() => ({}), {}); - return dispatch; + return useReducer(() => ({}), {})[1]; } diff --git a/src/State/useSync.ts b/src/State/useSync.ts index 3123882..91ac042 100644 --- a/src/State/useSync.ts +++ b/src/State/useSync.ts @@ -1,19 +1,31 @@ import { DependencyList, useRef } from 'react'; -import is from './is'; + +const intialValue: [any, DependencyList | undefined] = [undefined, undefined]; + +/** @ignore */ +function dependencyListIs(a: DependencyList | undefined, b: DependencyList | undefined): boolean { + if (!a || !b || a.length !== b.length) return false; + + for (let i = 0; i < a.length; ++i) { + if (!Object.is(a[i], b[i])) return false; + } + + return true; +} /** * @ignore * An alternative to React useMemo that provides a semantic guarantee of referential stability. + * This allows synchronous effects to be invoked safely during the render phase. * @param factory The factory function to compute a referentially stable value * @param deps The dependencies of the computation */ export default function useSync(factory: () => T, deps: DependencyList | undefined): T { - const { current } = useRef<[T?, DependencyList?]>([]); + const ref = useRef<[T, DependencyList | undefined]>(intialValue); - if (!is(current[1], deps)) { - current[0] = factory(); - current[1] = deps; + if (!dependencyListIs(ref.current[1], deps)) { + ref.current = [factory(), deps]; } - return current[0]!; + return ref.current[0]; } diff --git a/src/StateContext/Consumer/index.tsx b/src/StateContext/Consumer/index.tsx index e179826..66b65d7 100644 --- a/src/StateContext/Consumer/index.tsx +++ b/src/StateContext/Consumer/index.tsx @@ -14,7 +14,12 @@ export function createStateContextConsumer( ): StateContextConsumer { const StateConsumer: StateContextConsumer = ({ id, children }) => { const render = useCallback( - ([state, setState]: State) => children(state, setState), + (stateAndSetState: State) => { + const state = stateAndSetState[0]; + const setState = stateAndSetState[1]; + + return children(state, setState); + }, [children], );