UNPKG

react-instantsearch-core

Version:
93 lines (88 loc) 4.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useWidget = useWidget; var _react = require("react"); var _dequal = require("./dequal"); var _use = require("./use"); var _useInstantSearchContext = require("./useInstantSearchContext"); var _useIsomorphicLayoutEffect = require("./useIsomorphicLayoutEffect"); var _useRSCContext = require("./useRSCContext"); function useWidget(_ref) { var _waitingForResultsRef; var widget = _ref.widget, parentIndex = _ref.parentIndex, props = _ref.props, shouldSsr = _ref.shouldSsr; var waitingForResultsRef = (0, _useRSCContext.useRSCContext)(); var prevPropsRef = (0, _react.useRef)(props); (0, _react.useEffect)(function () { prevPropsRef.current = props; }, [props]); var prevWidgetRef = (0, _react.useRef)(widget); (0, _react.useEffect)(function () { prevWidgetRef.current = widget; }, [widget]); var cleanupTimerRef = (0, _react.useRef)(null); var shouldAddWidgetEarly = shouldSsr && !parentIndex.getWidgets().includes(widget); var search = (0, _useInstantSearchContext.useInstantSearchContext)(); // This effect is responsible for adding, removing, and updating the widget. // We need to support scenarios where the widget is remounted quickly, like in // Strict Mode, so that we don't lose its state, and therefore that we don't // break routing. (0, _useIsomorphicLayoutEffect.useIsomorphicLayoutEffect)(function () { var previousWidget = prevWidgetRef.current; // Scenario 1: the widget is added for the first time. if (!cleanupTimerRef.current) { if (!shouldSsr) { parentIndex.addWidgets([widget]); } } // Scenario 2: the widget is rerendered or updated. else { // We cancel the original effect cleanup because it may not be necessary if // props haven't changed. (We manually call it if it is below.) clearTimeout(cleanupTimerRef.current); // Warning: if an unstable function prop is provided, `dequal` is not able // to keep its reference and therefore will consider that props did change. // This could unsollicitely remove/add the widget, therefore forget its state, // and could be a source of confusion. // If users face this issue, we should advise them to provide stable function // references. var arePropsEqual = (0, _dequal.dequal)(props, prevPropsRef.current); // If props did change, then we execute the cleanup function instantly // and then add the widget back. This lets us add the widget without // waiting for the scheduled cleanup function to finish (that we canceled // above). if (!arePropsEqual) { parentIndex.removeWidgets([previousWidget]); parentIndex.addWidgets([widget]); } } return function () { // We don't remove the widget right away, but rather schedule it so that // we're able to cancel it in the next effect. cleanupTimerRef.current = setTimeout(function () { search._schedule(function () { if (search._preventWidgetCleanup) return; parentIndex.removeWidgets([previousWidget]); }); }); }; }, [parentIndex, widget, shouldSsr, search, props]); if (shouldAddWidgetEarly || (waitingForResultsRef === null || waitingForResultsRef === void 0 ? void 0 : (_waitingForResultsRef = waitingForResultsRef.current) === null || _waitingForResultsRef === void 0 ? void 0 : _waitingForResultsRef.status) === 'pending') { parentIndex.addWidgets([widget]); } if (typeof window === 'undefined' && waitingForResultsRef !== null && waitingForResultsRef !== void 0 && waitingForResultsRef.current && // We need the widgets contained in the index to be added before we trigger the search request. widget.$$type !== 'ais.index') { var _search$helper; (0, _use.use)(waitingForResultsRef.current); // If we made a second request because of DynamicWidgets, we need to wait for the second result, // except for DynamicWidgets itself which needs to render its children after the first result. if (widget.$$type !== 'ais.dynamicWidgets' && (_search$helper = search.helper) !== null && _search$helper !== void 0 && _search$helper.lastResults) { (0, _use.use)(waitingForResultsRef.current); } } }