diff --git a/src/connectors/infinite-hits/connectInfiniteHits.js b/src/connectors/infinite-hits/connectInfiniteHits.js
new file mode 100644
index 0000000000..c39fe3f49c
--- /dev/null
+++ b/src/connectors/infinite-hits/connectInfiniteHits.js
@@ -0,0 +1,107 @@
+import {
+ bemHelper,
+ prepareTemplateProps,
+ getContainerNode,
+} from '../../lib/utils.js';
+import cx from 'classnames';
+import defaultTemplates from './defaultTemplates.js';
+
+const bem = bemHelper('ais-infinite-hits');
+
+/**
+ * Display the list of results (hits) from the current search
+ * @function hits
+ * @param {string|DOMElement} options.container CSS Selector or DOMElement to insert the widget
+ * @param {number} [options.hitsPerPage=20] The number of hits to display per page [*]
+ * @param {Object} [options.templates] Templates to use for the widget
+ * @param {string|Function} [options.templates.empty=''] Template to use when there are no results.
+ * @param {string|Function} [options.templates.item=''] Template to use for each result. This template will receive an object containing a single record.
+ * @param {Object} [options.transformData] Method to change the object passed to the templates
+ * @param {Function} [options.transformData.empty] Method used to change the object passed to the `empty` template
+ * @param {Function} [options.transformData.item] Method used to change the object passed to the `item` template
+ * @param {Object} [options.cssClasses] CSS classes to add
+ * @param {string|string[]} [options.cssClasses.root] CSS class to add to the wrapping element
+ * @param {string|string[]} [options.cssClasses.empty] CSS class to add to the wrapping element when no results
+ * @param {string|string[]} [options.7cssClasses.item] CSS class to add to each result
+ * @return {Object}
+ */
+const usage = `
+Usage:
+infiniteHits({
+ container,
+ [ cssClasses.{root,empty,item}={} ],
+ [ templates.{empty,item} | templates.{empty} ],
+ [ transformData.{empty,item} | transformData.{empty} ],
+ [ hitsPerPage=20 ]
+})`;
+const connectInfiniteHits = infiniteHitsRendering => ({
+ container,
+ cssClasses: userCssClasses = {},
+ showMoreLabel = 'Show more results',
+ templates = defaultTemplates,
+ transformData,
+ hitsPerPage = 20,
+} = {}) => {
+ if (!container) {
+ throw new Error(`Must provide a container.${usage}`);
+ }
+
+ const containerNode = getContainerNode(container);
+ const cssClasses = {
+ root: cx(bem(null), userCssClasses.root),
+ item: cx(bem('item'), userCssClasses.item),
+ empty: cx(bem(null, 'empty'), userCssClasses.empty),
+ showmore: cx(bem('showmore'), userCssClasses.showmore),
+ };
+
+ let hitsCache = [];
+
+ const getShowMore = helper => () => helper.nextPage().search();
+
+ return {
+ getConfiguration: () => ({hitsPerPage}),
+ init({templatesConfig, helper}) {
+ this._templateProps = prepareTemplateProps({
+ transformData,
+ defaultTemplates,
+ templatesConfig,
+ templates,
+ });
+
+ this.showMore = getShowMore(helper);
+
+ infiniteHitsRendering({
+ cssClasses,
+ hits: hitsCache,
+ results: [],
+ showMore: this.showMore,
+ showMoreLabel,
+ templateProps: this._templateProps,
+ containerNode,
+ isLastPage: true,
+ }, true);
+ },
+ render({results, state}) {
+ if (state.page === 0) {
+ hitsCache = [];
+ }
+
+ hitsCache = [...hitsCache, ...results.hits];
+
+ const isLastPage = results.nbPages <= results.page + 1;
+
+ infiniteHitsRendering({
+ cssClasses,
+ hits: hitsCache,
+ results,
+ showMore: this.showMore,
+ showMoreLabel,
+ templateProps: this._templateProps,
+ containerNode,
+ isLastPage,
+ }, false);
+ },
+ };
+};
+
+export default connectInfiniteHits;
diff --git a/src/widgets/infinite-hits/defaultTemplates.js b/src/connectors/infinite-hits/defaultTemplates.js
similarity index 100%
rename from src/widgets/infinite-hits/defaultTemplates.js
rename to src/connectors/infinite-hits/defaultTemplates.js
diff --git a/src/widgets/infinite-hits/__tests__/defaultTemplates-test.js b/src/widgets/infinite-hits/__tests__/defaultTemplates-test.js
index e4cf82a0e9..8c0b6e3a92 100644
--- a/src/widgets/infinite-hits/__tests__/defaultTemplates-test.js
+++ b/src/widgets/infinite-hits/__tests__/defaultTemplates-test.js
@@ -2,7 +2,7 @@
import expect from 'expect';
-import defaultTemplates from '../defaultTemplates';
+import defaultTemplates from '../../../connectors/infinite-hits/defaultTemplates.js';
describe('hits defaultTemplates', () => {
it('has a `empty` default template', () => {
diff --git a/src/widgets/infinite-hits/__tests__/infinite-hits-test.js b/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
index 5d01dd17a9..214e3eba96 100644
--- a/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
+++ b/src/widgets/infinite-hits/__tests__/infinite-hits-test.js
@@ -11,6 +11,8 @@ import algoliasearchHelper from 'algoliasearch-helper';
import infiniteHits from '../infinite-hits';
import InfiniteHits from '../../../components/InfiniteHits';
+import defaultTemplates from '../../../connectors/infinite-hits/defaultTemplates.js';
+
describe('infiniteHits call', () => {
it('throws an exception when no container', () => {
expect(infiniteHits).toThrow(/^Must provide a container/);
@@ -25,10 +27,6 @@ describe('infiniteHits()', () => {
let results;
let props;
let helper;
- const defaultTemplates = {
- hit: 'hit',
- empty: 'empty',
- };
beforeEach(() => {
helper = algoliasearchHelper({addAlgoliaAgent: () => {}});
@@ -36,14 +34,13 @@ describe('infiniteHits()', () => {
ReactDOM = {render: sinon.spy()};
infiniteHits.__Rewire__('ReactDOM', ReactDOM);
- infiniteHits.__Rewire__('defaultTemplates', defaultTemplates);
container = document.createElement('div');
templateProps = {
transformData: undefined,
templatesConfig: undefined,
templates: defaultTemplates,
- useCustomCompileOptions: {hit: false, empty: false},
+ useCustomCompileOptions: {item: false, empty: false},
};
widget = infiniteHits({container, cssClasses: {root: ['root', 'cx']}});
widget.init({helper});
diff --git a/src/widgets/infinite-hits/infinite-hits.js b/src/widgets/infinite-hits/infinite-hits.js
index a90d5ae600..67bec2e81f 100644
--- a/src/widgets/infinite-hits/infinite-hits.js
+++ b/src/widgets/infinite-hits/infinite-hits.js
@@ -1,15 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import {
- bemHelper,
- prepareTemplateProps,
- getContainerNode,
-} from '../../lib/utils.js';
-import cx from 'classnames';
import InfiniteHits from '../../components/InfiniteHits.js';
-import defaultTemplates from './defaultTemplates.js';
-const bem = bemHelper('ais-infinite-hits');
+import connectInfiniteHits from '../../connectors/infinite-hits/connectInfiniteHits.js';
/**
* Display the list of results (hits) from the current search
@@ -29,75 +22,30 @@ const bem = bemHelper('ais-infinite-hits');
* @param {string|string[]} [options.cssClasses.item] CSS class to add to each result
* @return {Object}
*/
-const usage = `
-Usage:
-infiniteHits({
- container,
- [ cssClasses.{root,empty,item}={} ],
- [ templates.{empty,item} | templates.{empty} ],
- [ showMoreLabel="Show more results" ]
- [ transformData.{empty,item} | transformData.{empty} ],
- [ hitsPerPage=20 ]
-})`;
-function infiniteHits({
- container,
- cssClasses: userCssClasses = {},
- showMoreLabel = 'Show more results',
- templates = defaultTemplates,
- transformData,
- hitsPerPage = 20,
- } = {}) {
- if (!container) {
- throw new Error(`Must provide a container.${usage}`);
- }
-
- const containerNode = getContainerNode(container);
- const cssClasses = {
- root: cx(bem(null), userCssClasses.root),
- item: cx(bem('item'), userCssClasses.item),
- empty: cx(bem(null, 'empty'), userCssClasses.empty),
- showmore: cx(bem('showmore'), userCssClasses.showmore),
- };
-
- let hitsCache = [];
-
- const getShowMore = helper => () => helper.nextPage().search();
-
- return {
- getConfiguration: () => ({hitsPerPage}),
- init({templatesConfig, helper}) {
- this._templateProps = prepareTemplateProps({
- transformData,
- defaultTemplates,
- templatesConfig,
- templates,
- });
-
- this.showMore = getShowMore(helper);
- },
- render({results, state}) {
- if (state.page === 0) {
- hitsCache = [];
- }
-
- hitsCache = [...hitsCache, ...results.hits];
-
- const isLastPage = results.nbPages <= results.page + 1;
-
- ReactDOM.render(
- ,
- containerNode
- );
- },
- };
+export default connectInfiniteHits(defaultRendering);
+
+function defaultRendering({
+ cssClasses,
+ hits,
+ results,
+ showMore,
+ showMoreLabel,
+ templateProps,
+ isLastPage,
+ containerNode,
+}, isFirstRendering) {
+ if (isFirstRendering) return;
+
+ ReactDOM.render(
+ ,
+ containerNode
+ );
}
-
-export default infiniteHits;