From 7d83c7c7ab7b9d4dffe9ac8baf3a44a0072258cb Mon Sep 17 00:00:00 2001 From: Andrew Musgrave Date: Wed, 18 Sep 2019 18:53:23 -0400 Subject: [PATCH 1/2] Add useLazyRef --- src/utilities/tests/use-lazy-ref.test.tsx | 37 +++++++++++++++++++++++ src/utilities/use-lazy-ref.ts | 22 ++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/utilities/tests/use-lazy-ref.test.tsx create mode 100644 src/utilities/use-lazy-ref.ts diff --git a/src/utilities/tests/use-lazy-ref.test.tsx b/src/utilities/tests/use-lazy-ref.test.tsx new file mode 100644 index 00000000000..f5933d9f88c --- /dev/null +++ b/src/utilities/tests/use-lazy-ref.test.tsx @@ -0,0 +1,37 @@ +import React, {useEffect, useState} from 'react'; +import {mount} from 'test-utilities'; +import {useLazyRef} from '../use-lazy-ref'; + +describe('useLazyRef', () => { + it('returns a ref object', () => { + const spy = jest.fn(); + + function MockComponent() { + const lazyValue = useLazyRef(() => true); + spy(lazyValue); + return null; + } + + mount(); + expect(spy).toHaveBeenCalledWith({current: true}); + }); + + it('only calls initialValue once', () => { + const spy = jest.fn(); + + function MockComponent() { + const [, setFooState] = useState(false); + + useEffect(() => { + setFooState(true); + }, []); + + useLazyRef(spy); + + return null; + } + + mount(); + expect(spy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/utilities/use-lazy-ref.ts b/src/utilities/use-lazy-ref.ts new file mode 100644 index 00000000000..7c84c56d0ae --- /dev/null +++ b/src/utilities/use-lazy-ref.ts @@ -0,0 +1,22 @@ +import {useRef, MutableRefObject} from 'react'; + +const UNIQUE_IDENTIFIER = Symbol('unique_identifier'); + +/** + * useLazyRef provides a lazy initial value, similar to lazy + * initial state the initialValue is the value used during + * initialization and disregarded after that. + * @param initialValue - A function that will return the initial + * value and be disregarded after that + * @returns MutableRefObject - Returns a ref object with the + * results from invoking initial value + */ +export function useLazyRef(initialValue: () => T) { + const lazyRef = useRef(UNIQUE_IDENTIFIER); + + if (lazyRef.current === UNIQUE_IDENTIFIER) { + lazyRef.current = initialValue(); + } + + return lazyRef as MutableRefObject; +} From 3a28fedfb1f96deffabdf7fc8f669c155724b399 Mon Sep 17 00:00:00 2001 From: Andrew Musgrave Date: Wed, 18 Sep 2019 19:40:18 -0400 Subject: [PATCH 2/2] changelog --- UNRELEASED.md | 1 + 1 file changed, 1 insertion(+) diff --git a/UNRELEASED.md b/UNRELEASED.md index b208c8e2cb5..8a5114d669c 100644 --- a/UNRELEASED.md +++ b/UNRELEASED.md @@ -45,6 +45,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f ### Code quality +- Added `useLazyRef` hook to use while building components ([#2166](https://github.com/Shopify/polaris-react/pull/2166)) - Migrated `FilterCreator` to use hooks instead of withAppProvider ([#2156](https://github.com/Shopify/polaris-react/pull/2156)) - Created a custom error for lack of context providers ([#2136](https://github.com/Shopify/polaris-react/pull/2136)) - Migrated `ContextualSaveBar` to use hooks instead of `withAppProvider` ([#2091](https://github.com/Shopify/polaris-react/pull/2091))