Skip to content

Commit

Permalink
invoke listeners in render, follows dai-shi/reactive-react-redux#31
Browse files Browse the repository at this point in the history
  • Loading branch information
sabugaa0128 committed Jul 20, 2019
1 parent b343176 commit fd46a4e
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 35 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change Log

## [Unreleased]
### Changed
- No useLayoutEffect for invoking listeners (which leads de-opt sync mode)

## [0.6.0] - 2019-07-15
### Changed
Expand Down
10 changes: 5 additions & 5 deletions src/Provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
useRef,
} from 'react';

import { useIsomorphicLayoutEffect } from './utils';

// -------------------------------------------------------
// context
// -------------------------------------------------------
Expand Down Expand Up @@ -54,9 +52,11 @@ export const createProvider = (customContext, customUseValue) => ({
}
const [state, dispatch] = useValue();
const listeners = useRef([]);
useIsomorphicLayoutEffect(() => {
listeners.current.forEach(listener => listener(state));
}, [state]);
// we call listeners in render intentionally.
// listeners are not technically pure, but
// otherwise we can't get benefits from concurrent mode.
// we make sure to work with double or more invocation of listeners.
listeners.current.forEach(listener => listener(state));
const subscribe = useCallback((listener) => {
listeners.current.push(listener);
const unsubscribe = () => {
Expand Down
21 changes: 8 additions & 13 deletions src/useSelector.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import {
useContext,
useEffect,
useRef,
} from 'react';

import { defaultContext } from './Provider';

import { useIsomorphicLayoutEffect, useForceUpdate } from './utils';

const defaultEqualityFn = (a, b) => a === b;
Expand All @@ -26,23 +24,20 @@ export const createUseSelector = customContext => (
selected,
};
});
useEffect(() => {
useIsomorphicLayoutEffect(() => {
const callback = (nextState) => {
if (ref.current.state === nextState) return;
let changed;
try {
changed = !ref.current.equalityFn(ref.current.selected, ref.current.selector(nextState));
if (ref.current.state === nextState
|| ref.current.equalityFn(ref.current.selected, ref.current.selector(nextState))) {
// not changed
return;
}
} catch (e) {
changed = true; // stale props or some other reason
}
if (changed) {
ref.current.state = nextState;
forceUpdate();
// ignored (stale props or some other reason)
}
forceUpdate();
};
const unsubscribe = subscribe(callback);
// force update in case the state is already changed
forceUpdate();
return unsubscribe;
}, [subscribe, forceUpdate]);
return selected;
Expand Down
29 changes: 12 additions & 17 deletions src/useTrackedState.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import {
useContext,
useEffect,
useMemo,
useRef,
} from 'react';

import { defaultContext } from './Provider';

import { useIsomorphicLayoutEffect, useForceUpdate } from './utils';

import { createDeepProxy, isDeepChanged } from './deepProxy';

import { createUseDispatch } from './useDispatch';

export const createUseTrackedState = customContext => (opts = {}) => {
Expand All @@ -31,23 +27,22 @@ export const createUseTrackedState = customContext => (opts = {}) => {
/* eslint-enable no-nested-ternary, indent, @typescript-eslint/indent */
};
});
useEffect(() => {
useIsomorphicLayoutEffect(() => {
const callback = (nextState) => {
const changed = isDeepChanged(
lastTracked.current.state,
nextState,
lastTracked.current.affected,
lastTracked.current.cache,
lastTracked.current.assumeChangedIfNotAffected,
);
if (changed) {
lastTracked.current.state = nextState;
forceUpdate();
if (lastTracked.current.state === nextState
|| !isDeepChanged(
lastTracked.current.state,
nextState,
lastTracked.current.affected,
lastTracked.current.cache,
lastTracked.current.assumeChangedIfNotAffected,
)) {
// not changed
return;
}
forceUpdate();
};
const unsubscribe = subscribe(callback);
// force update in case the state is already changed
forceUpdate();
return unsubscribe;
}, [subscribe, forceUpdate]);
const proxyCache = useRef(new WeakMap()); // per-hook proxyCache
Expand Down

0 comments on commit fd46a4e

Please sign in to comment.