From 1bc3c6f1da5e8aaf8b656fabfbbb9ecafb4e7f87 Mon Sep 17 00:00:00 2001 From: daishi Date: Mon, 24 Feb 2020 10:57:36 +0900 Subject: [PATCH] A temporal workaround with useLayoutEffect in DEV (https://github.com/dai-shi/use-context-selector/pull/13) --- CHANGELOG.md | 2 ++ dist/Provider.js | 33 +++++++++++++++++++++++++-------- src/Provider.js | 23 ++++++++++++++++++----- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdc354c..0bce8b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Change Log ## [Unreleased] +### Changed +- A workaround for React render warning (hopefully temporarily) ## [4.5.0] - 2020-02-03 ### Changed diff --git a/dist/Provider.js b/dist/Provider.js index 9283e33..5680770 100644 --- a/dist/Provider.js +++ b/dist/Provider.js @@ -63,14 +63,29 @@ var Provider = function Provider(_ref) { forceUpdate = _useReducer2[1]; var state = store.getState(); - var listeners = (0, _react.useRef)([]); // 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(function (listener) { - return listener(state); - }); + var listeners = (0, _react.useRef)([]); + + if (process.env.NODE_ENV !== 'production') { + // we use layout effect to eliminate warnings. + // but, this leads tearing with startTransition. + // https://github.com/dai-shi/use-context-selector/pull/13 + // eslint-disable-next-line react-hooks/rules-of-hooks + (0, _react.useLayoutEffect)(function () { + listeners.current.forEach(function (listener) { + return listener(state); + }); + }); + } else { + // we call listeners in render for optimization. + // although this is not a recommended pattern, + // so far this is only the way to make it as expected. + // we are looking for better solutions. + // https://github.com/dai-shi/use-context-selector/pull/12 + listeners.current.forEach(function (listener) { + return listener(state); + }); + } + var subscribe = (0, _react.useCallback)(function (listener) { listeners.current.push(listener); @@ -87,6 +102,8 @@ var Provider = function Provider(_ref) { var unsubscribe = store.subscribe(function () { forceUpdate(); }); + forceUpdate(); // in case it's already changed + return unsubscribe; }, [store]); return (0, _react.createElement)(customContext.Provider, { diff --git a/src/Provider.js b/src/Provider.js index 381b4a8..8e17fbc 100644 --- a/src/Provider.js +++ b/src/Provider.js @@ -2,6 +2,7 @@ import { createContext, createElement, useCallback, + useLayoutEffect, useEffect, useRef, useReducer, @@ -46,11 +47,22 @@ export const Provider = ({ const [, forceUpdate] = useReducer((c) => c + 1, 0); const state = store.getState(); const listeners = useRef([]); - // 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)); + if (process.env.NODE_ENV !== 'production') { + // we use layout effect to eliminate warnings. + // but, this leads tearing with startTransition. + // https://github.com/dai-shi/use-context-selector/pull/13 + // eslint-disable-next-line react-hooks/rules-of-hooks + useLayoutEffect(() => { + listeners.current.forEach((listener) => listener(state)); + }); + } else { + // we call listeners in render for optimization. + // although this is not a recommended pattern, + // so far this is only the way to make it as expected. + // we are looking for better solutions. + // https://github.com/dai-shi/use-context-selector/pull/12 + listeners.current.forEach((listener) => listener(state)); + } const subscribe = useCallback((listener) => { listeners.current.push(listener); const unsubscribe = () => { @@ -65,6 +77,7 @@ export const Provider = ({ const unsubscribe = store.subscribe(() => { forceUpdate(); }); + forceUpdate(); // in case it's already changed return unsubscribe; }, [store]); return createElement(