From 63cc7d2b31b4e5ad17c07b383a328c598c91276e Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 15 Oct 2018 17:20:05 -0400 Subject: [PATCH] Test useContext in pure, forwardRef, and PureComponent --- .../ReactNewContext-test.internal.js | 91 ++++++++++++------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index 25c3a3a1ad..4ebcd1f84d 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -57,6 +57,25 @@ describe('ReactNewContext', () => { return render(contextValue); }, ); + sharedContextTests('useContext inside forwardRef component', Context => + React.forwardRef(function Consumer(props, ref) { + const observedBits = props.unstable_observedBits; + const contextValue = useContext(Context, observedBits); + const render = props.children; + return render(contextValue); + }), + ); + sharedContextTests( + 'useContext inside memoized function component', + Context => + React.memo(function Consumer(props) { + const observedBits = props.unstable_observedBits; + const contextValue = useContext(Context, observedBits); + const render = props.children; + return render(contextValue); + }), + true, + ); sharedContextTests( 'readContext(Context) inside class component', Context => @@ -70,7 +89,7 @@ describe('ReactNewContext', () => { }, ); - function sharedContextTests(label, getConsumer) { + function sharedContextTests(label, getConsumer, isPure) { describe(`reading context with ${label}`, () => { it('simple mount and update', () => { const Context = React.createContext(1); @@ -855,46 +874,48 @@ describe('ReactNewContext', () => { expect(ReactNoop.getChildren()).toEqual([span(2), span(2)]); }); - // Context consumer bails out on propagating "deep" updates when `value` hasn't changed. - // However, it doesn't bail out from rendering if the component above it re-rendered anyway. - // If we bailed out on referential equality, it would be confusing that you - // can call this.setState(), but an autobound render callback "blocked" the update. - // https://github.com/facebook/react/pull/12470#issuecomment-376917711 - it('consumer does not bail out if there were no bailouts above it', () => { - const Context = React.createContext(0); - const Consumer = getConsumer(Context); + if (!isPure) { + // Context consumer bails out on propagating "deep" updates when `value` hasn't changed. + // However, it doesn't bail out from rendering if the component above it re-rendered anyway. + // If we bailed out on referential equality, it would be confusing that you + // can call this.setState(), but an autobound render callback "blocked" the update. + // https://github.com/facebook/react/pull/12470#issuecomment-376917711 + it('consumer does not bail out if there were no bailouts above it', () => { + const Context = React.createContext(0); + const Consumer = getConsumer(Context); - class App extends React.Component { - state = { - text: 'hello', - }; + class App extends React.Component { + state = { + text: 'hello', + }; - renderConsumer = context => { - ReactNoop.yield('App#renderConsumer'); - return ; - }; + renderConsumer = context => { + ReactNoop.yield('App#renderConsumer'); + return ; + }; - render() { - ReactNoop.yield('App'); - return ( - - {this.renderConsumer} - - ); + render() { + ReactNoop.yield('App'); + return ( + + {this.renderConsumer} + + ); + } } - } - // Initial mount - let inst; - ReactNoop.render( (inst = ref)} />); - expect(ReactNoop.flush()).toEqual(['App', 'App#renderConsumer']); - expect(ReactNoop.getChildren()).toEqual([span('hello')]); + // Initial mount + let inst; + ReactNoop.render( (inst = ref)} />); + expect(ReactNoop.flush()).toEqual(['App', 'App#renderConsumer']); + expect(ReactNoop.getChildren()).toEqual([span('hello')]); - // Update - inst.setState({text: 'goodbye'}); - expect(ReactNoop.flush()).toEqual(['App', 'App#renderConsumer']); - expect(ReactNoop.getChildren()).toEqual([span('goodbye')]); - }); + // Update + inst.setState({text: 'goodbye'}); + expect(ReactNoop.flush()).toEqual(['App', 'App#renderConsumer']); + expect(ReactNoop.getChildren()).toEqual([span('goodbye')]); + }); + } // This is a regression case for https://github.com/facebook/react/issues/12389. it('does not run into an infinite loop', () => {