From 24c3bb418df9cbc3a5e57ee34796a9c501e05f48 Mon Sep 17 00:00:00 2001 From: yoyo837 Date: Thu, 10 Jun 2021 18:36:17 +0800 Subject: [PATCH 1/4] feat: add useLayoutEffect hook --- src/hooks/useLayoutEffect.ts | 17 +++++++++++++++++ src/isBrowserClient.ts | 4 ++++ 2 files changed, 21 insertions(+) create mode 100644 src/hooks/useLayoutEffect.ts create mode 100644 src/isBrowserClient.ts diff --git a/src/hooks/useLayoutEffect.ts b/src/hooks/useLayoutEffect.ts new file mode 100644 index 00000000..f0ea4e6f --- /dev/null +++ b/src/hooks/useLayoutEffect.ts @@ -0,0 +1,17 @@ +/* eslint-disable react-hooks/rules-of-hooks */ +import * as React from 'react'; +import isBrowserClient from 'src/isBrowserClient'; + +/** + * Wrap `React.useLayoutEffect` which will not throw warning message in test env + */ +export default function useLayoutEffect(effect: React.EffectCallback, deps?: React.DependencyList) { + // Never happen in test env + if (isBrowserClient) { + /* istanbul ignore next */ + React.useLayoutEffect(effect, deps); + } else { + React.useEffect(effect, deps); + } +} +/* eslint-enable */ diff --git a/src/isBrowserClient.ts b/src/isBrowserClient.ts new file mode 100644 index 00000000..49bd73f7 --- /dev/null +++ b/src/isBrowserClient.ts @@ -0,0 +1,4 @@ +import canUseDom from './Dom/canUseDom'; + +/** Is client side and not jsdom */ +export default process.env.NODE_ENV !== 'test' && canUseDom(); From d571a9f0890de505f08b9e42e41927c428e90623 Mon Sep 17 00:00:00 2001 From: yoyo837 Date: Thu, 10 Jun 2021 18:40:15 +0800 Subject: [PATCH 2/4] fix path --- src/hooks/useLayoutEffect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useLayoutEffect.ts b/src/hooks/useLayoutEffect.ts index f0ea4e6f..c0d04e14 100644 --- a/src/hooks/useLayoutEffect.ts +++ b/src/hooks/useLayoutEffect.ts @@ -1,6 +1,6 @@ /* eslint-disable react-hooks/rules-of-hooks */ import * as React from 'react'; -import isBrowserClient from 'src/isBrowserClient'; +import isBrowserClient from '../isBrowserClient'; /** * Wrap `React.useLayoutEffect` which will not throw warning message in test env From 10a1f5a18443ada792c97a80bc0a31d8854c8f43 Mon Sep 17 00:00:00 2001 From: yoyo837 Date: Thu, 10 Jun 2021 19:08:37 +0800 Subject: [PATCH 3/4] add test case --- tests/hooks.test.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/hooks.test.js b/tests/hooks.test.js index 40dc81c1..b2f73f0d 100644 --- a/tests/hooks.test.js +++ b/tests/hooks.test.js @@ -2,6 +2,7 @@ import * as React from 'react'; import { mount } from 'enzyme'; import useMemo from '../src/hooks/useMemo'; import useMergedState from '../src/hooks/useMergedState'; +import useLayoutEffect from '../src/hooks/useLayoutEffect'; describe('hooks', () => { it('useMemo', () => { @@ -56,4 +57,33 @@ describe('hooks', () => { expect(wrapper.find('input').props().value).toEqual('test'); }); }); + + describe('useLayoutEffect', () => { + const FC = ({ defaultValue }) => { + const [val, setVal] = React.useState(defaultValue); + const [val2, setVal2] = React.useState(); + useLayoutEffect(() => { + setVal2(`${val}a`); + }, [val]); + return ( +
+ { + setVal(e.target.value); + }} + /> + +
+ ); + }; + + it('correct effect', () => { + const wrapper = mount(); + expect(wrapper.find('label').props().children).toEqual('testa'); + wrapper.find('input').simulate('change', { target: { value: '1' } }); + wrapper.update(); + expect(wrapper.find('label').props().children).toEqual('1a'); + }); + }); }); From febba57e27f89655a5a985eab478e638c4024fff Mon Sep 17 00:00:00 2001 From: yoyo837 Date: Thu, 10 Jun 2021 19:11:09 +0800 Subject: [PATCH 4/4] update test case --- tests/hooks.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/hooks.test.js b/tests/hooks.test.js index b2f73f0d..a9222f34 100644 --- a/tests/hooks.test.js +++ b/tests/hooks.test.js @@ -84,6 +84,9 @@ describe('hooks', () => { wrapper.find('input').simulate('change', { target: { value: '1' } }); wrapper.update(); expect(wrapper.find('label').props().children).toEqual('1a'); + wrapper.find('input').simulate('change', { target: { value: '2' } }); + wrapper.update(); + expect(wrapper.find('label').props().children).toEqual('2a'); }); }); });