Skip to content

Commit

Permalink
Tidied things up, added Flow types, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
Brian Vaughn committed Mar 7, 2019
1 parent 8fa0898 commit b3e8a0a
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
33 changes: 11 additions & 22 deletions packages/react-hooks/src/__tests__/useSubscription-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,16 @@ describe('useSubscription', () => {

// Mimic createSubscription API to simplify testing
function createSubscription({getCurrentValue, subscribe}) {
function DefaultChild({value = 'default'}) {
Scheduler.yieldValue(value);
return null;
}

return function Subscription({children, source}) {
const value = useSubscription(
React.useMemo(() => ({source, getCurrentValue, subscribe}), [source]),
);

return React.createElement(children, {value});
return React.createElement(children || DefaultChild, {value});
};
}

Expand All @@ -71,12 +75,7 @@ describe('useSubscription', () => {

const observable = createBehaviorSubject();
const renderer = ReactTestRenderer.create(
<Subscription source={observable}>
{({value = 'default'}) => {
Scheduler.yieldValue(value);
return null;
}}
</Subscription>,
<Subscription source={observable} />,
{unstable_isConcurrent: true},
);

Expand Down Expand Up @@ -110,14 +109,9 @@ describe('useSubscription', () => {
},
});

function render({value = 'default'}) {
Scheduler.yieldValue(value);
return null;
}

let observable = createReplaySubject('initial');
const renderer = ReactTestRenderer.create(
<Subscription source={observable}>{render}</Subscription>,
<Subscription source={observable} />,
{unstable_isConcurrent: true},
);
expect(Scheduler).toFlushAndYield(['initial']);
Expand All @@ -128,7 +122,7 @@ describe('useSubscription', () => {

// Unsetting the subscriber prop should reset subscribed values
observable = createReplaySubject(undefined);
renderer.update(<Subscription source={observable}>{render}</Subscription>);
renderer.update(<Subscription source={observable} />);
expect(Scheduler).toFlushAndYield(['default']);
});

Expand All @@ -141,24 +135,19 @@ describe('useSubscription', () => {
},
});

function render({value = 'default'}) {
Scheduler.yieldValue(value);
return null;
}

const observableA = createBehaviorSubject('a-0');
const observableB = createBehaviorSubject('b-0');

const renderer = ReactTestRenderer.create(
<Subscription source={observableA}>{render}</Subscription>,
<Subscription source={observableA} />,
{unstable_isConcurrent: true},
);

// Updates while subscribed should re-render the child component
expect(Scheduler).toFlushAndYield(['a-0']);

// Unsetting the subscriber prop should reset subscribed values
renderer.update(<Subscription source={observableB}>{render}</Subscription>);
renderer.update(<Subscription source={observableB} />);
expect(Scheduler).toFlushAndYield(['b-0']);

// Updates to the old subscribable should not re-render the child component
Expand Down
23 changes: 21 additions & 2 deletions packages/react-hooks/src/useSubscription.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import {useEffect, useState} from 'react';

export function useSubscription({
// Hook used for safely managing subscriptions in concurrent mode.
//
// In order to avoid removing and re-adding subscriptions each time this hook is called,
// the parameters passed to this hook should be memoized in some way–
// either by wrapping the entire params object with useMemo()
// or by wrapping the individual callbacks with useCallback().
export function useSubscription<Value, Source>({
// This is the thing being subscribed to (e.g. an observable, event dispatcher, etc).
source,

Expand All @@ -10,7 +25,11 @@ export function useSubscription({
// This function is passed an event handler to attach to the subscription source.
// It should return an unsubscribe function that removes the handler.
subscribe,
}) {
}: {|
source: Source,
getCurrentValue: (source: Source) => Value,
subscribe: (source: Source, callback: Function) => () => void,
|}) {
// Read the current value from our subscription source.
// When this value changes, we'll schedule an update with React.
// It's important to also store the source itself so that we can check for staleness.
Expand Down

0 comments on commit b3e8a0a

Please sign in to comment.