Skip to content

Commit

Permalink
backport #3663
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Sep 2, 2022
1 parent 4ea4f93 commit dbed283
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 10 deletions.
29 changes: 22 additions & 7 deletions compat/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,24 +137,39 @@ export function useTransition() {
// styles/... before it attaches
export const useInsertionEffect = useLayoutEffect;

/**
* This is taken from https://github.com/facebook/react/blob/main/packages/use-sync-external-store/src/useSyncExternalStoreShimClient.js#L84
* on a high level this cuts out the warnings, ... and attempts a smaller implementation
*/
export function useSyncExternalStore(subscribe, getSnapshot) {
const [state, setState] = useState(getSnapshot);

const value = getSnapshot();

const [{ _instance }, forceUpdate] = useState({
_instance: { _value: value, _getSnapshot: getSnapshot }
});

useLayoutEffect(() => {
if (value !== state) {
setState(() => value);
_instance._value = value;
_instance._getSnapshot = getSnapshot;

if (_instance._value !== getSnapshot()) {
forceUpdate({ _instance });
}
}, [subscribe, value, getSnapshot]);

useEffect(() => {
if (_instance._value !== _instance._getSnapshot()) {
forceUpdate({ _instance });
}

return subscribe(() => {
setState(() => getSnapshot());
if (_instance._value !== _instance._getSnapshot()) {
forceUpdate({ _instance });
}
});
}, [subscribe, getSnapshot]);
}, [subscribe]);

return state;
return value;
}

export * from 'preact/hooks';
Expand Down
34 changes: 31 additions & 3 deletions compat/test/browser/hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ describe('React-18-hooks', () => {
});
expect(scratch.innerHTML).to.equal('<p>hello world</p>');
expect(subscribe).to.be.calledOnce;
expect(getSnapshot).to.be.calledTwice;
expect(getSnapshot).to.be.calledThrice;
});

it('subscribes and rerenders when called', () => {
Expand Down Expand Up @@ -121,7 +121,7 @@ describe('React-18-hooks', () => {
});
expect(scratch.innerHTML).to.equal('<p>hello world</p>');
expect(subscribe).to.be.calledOnce;
expect(getSnapshot).to.be.calledTwice;
expect(getSnapshot).to.be.calledThrice;

called = true;
flush();
Expand Down Expand Up @@ -154,14 +154,42 @@ describe('React-18-hooks', () => {
});
expect(scratch.innerHTML).to.equal('<p>value: 0</p>');
expect(subscribe).to.be.calledOnce;
expect(getSnapshot).to.be.calledTwice;
expect(getSnapshot).to.be.calledThrice;

flush();
rerender();

expect(scratch.innerHTML).to.equal('<p>value: 0</p>');
});

it('should work with changing getSnapshot', () => {
let flush;
const subscribe = sinon.spy(cb => {
flush = cb;
return () => {};
});

let i = 0;
const App = () => {
const value = useSyncExternalStore(subscribe, () => {
return i;
});
return <p>value: {value}</p>;
};

act(() => {
render(<App />, scratch);
});
expect(scratch.innerHTML).to.equal('<p>value: 0</p>');
expect(subscribe).to.be.calledOnce;

i++;
flush();
rerender();

expect(scratch.innerHTML).to.equal('<p>value: 1</p>');
});

it('works with useCallback', () => {
let toggle;
const App = () => {
Expand Down

0 comments on commit dbed283

Please sign in to comment.