diff --git a/packages/react-instantsearch/src/core/InstantSearch.js b/packages/react-instantsearch/src/core/InstantSearch.js
index dba56b7fe5..1c27f483fd 100644
--- a/packages/react-instantsearch/src/core/InstantSearch.js
+++ b/packages/react-instantsearch/src/core/InstantSearch.js
@@ -26,6 +26,7 @@ function validateNextProps(props, nextProps) {
* @propType {string} appId - Your Algolia application id.
* @propType {string} apiKey - Your Algolia search-only API key.
* @propType {string} indexName - Main index in which to search.
+ * @propType {boolean} [refresh=false] - Flag to activate when the cache needs to be cleared so that the front-end is updated when a change occurs in the index.
* @propType {object} [algoliaClient] - Provide a custom Algolia client instead of the internal one.
* @propType {func} [onSearchStateChange] - Function to be called everytime a new search is done. Useful for [URL Routing](guide/Routing.html).
* @propType {object} [searchState] - Object to inject some search state. Switches the InstantSearch component in controlled mode. Useful for [URL Routing](guide/Routing.html).
@@ -70,6 +71,12 @@ class InstantSearch extends Component {
this.aisManager.updateIndex(nextProps.indexName);
}
+ if (this.props.refresh !== nextProps.refresh) {
+ if (nextProps.refresh) {
+ this.aisManager.clearCache();
+ }
+ }
+
if (this.props.algoliaClient !== nextProps.algoliaClient) {
this.aisManager.updateClient(nextProps.algoliaClient);
}
@@ -170,6 +177,8 @@ InstantSearch.propTypes = {
createURL: PropTypes.func,
+ refresh: PropTypes.bool.isRequired,
+
searchState: PropTypes.object,
onSearchStateChange: PropTypes.func,
diff --git a/packages/react-instantsearch/src/core/InstantSearch.test.js b/packages/react-instantsearch/src/core/InstantSearch.test.js
index 5d03d30ca9..5c1c8dec4d 100644
--- a/packages/react-instantsearch/src/core/InstantSearch.test.js
+++ b/packages/react-instantsearch/src/core/InstantSearch.test.js
@@ -9,6 +9,7 @@ Enzyme.configure({ adapter: new Adapter() });
import InstantSearch from './InstantSearch';
import createInstantSearchManager from './createInstantSearchManager';
+
jest.mock('./createInstantSearchManager', () =>
jest.fn(() => ({
context: {},
@@ -24,6 +25,7 @@ const DEFAULT_PROPS = {
root: {
Root: 'div',
},
+ refresh: false,
};
describe('InstantSearch', () => {
@@ -60,6 +62,7 @@ describe('InstantSearch', () => {
searchState={{}}
onSearchStateChange={() => null}
createURL={() => null}
+ refresh={false}
>
@@ -139,6 +142,7 @@ describe('InstantSearch', () => {
...DEFAULT_PROPS,
algoliaClient: {},
});
+
expect(ism.updateClient.mock.calls).toHaveLength(1);
});
@@ -255,6 +259,64 @@ describe('InstantSearch', () => {
expect(ism.skipSearch.mock.calls).toHaveLength(1);
});
+ it('refreshes the cache when the refresh prop is set to true', () => {
+ const ism = {
+ clearCache: jest.fn(),
+ };
+
+ createInstantSearchManager.mockImplementation(() => ism);
+
+ const wrapper = shallow(
+
+
+
+ );
+
+ expect(ism.clearCache).not.toHaveBeenCalled();
+
+ wrapper.setProps({
+ ...DEFAULT_PROPS,
+ refresh: false,
+ });
+
+ expect(ism.clearCache).not.toHaveBeenCalled();
+
+ wrapper.setProps({
+ ...DEFAULT_PROPS,
+ refresh: true,
+ });
+
+ expect(ism.clearCache).toHaveBeenCalledTimes(1);
+ });
+
+ it('updates the index when the the index changes', () => {
+ const ism = {
+ updateIndex: jest.fn(),
+ };
+
+ createInstantSearchManager.mockImplementation(() => ism);
+
+ const wrapper = shallow(
+
+
+
+ );
+
+ expect(ism.updateIndex).not.toHaveBeenCalled();
+
+ wrapper.setProps({
+ indexName: 'foobar',
+ });
+
+ expect(ism.updateIndex).not.toHaveBeenCalled();
+
+ wrapper.setProps({
+ indexName: 'newindexname',
+ });
+
+ expect(ism.updateIndex).toHaveBeenCalledTimes(1);
+ });
+
it('calls onSearchParameters with the right values if function provided', () => {
const ism = {
store: {},
diff --git a/packages/react-instantsearch/src/core/__snapshots__/createInstantSearch.test.js.snap b/packages/react-instantsearch/src/core/__snapshots__/createInstantSearch.test.js.snap
index dee49c5446..76c1672fdc 100644
--- a/packages/react-instantsearch/src/core/__snapshots__/createInstantSearch.test.js.snap
+++ b/packages/react-instantsearch/src/core/__snapshots__/createInstantSearch.test.js.snap
@@ -10,6 +10,7 @@ Object {
"indexName": "name",
"onSearchParameters": undefined,
"onSearchStateChange": undefined,
+ "refresh": false,
"resultsState": undefined,
"root": Object {
"Root": "div",
diff --git a/packages/react-instantsearch/src/core/createInstantSearch.js b/packages/react-instantsearch/src/core/createInstantSearch.js
index c305db4ace..cc2e2dde8c 100644
--- a/packages/react-instantsearch/src/core/createInstantSearch.js
+++ b/packages/react-instantsearch/src/core/createInstantSearch.js
@@ -24,11 +24,16 @@ export default function createInstantSearch(defaultAlgoliaClient, root) {
searchParameters: PropTypes.object,
createURL: PropTypes.func,
searchState: PropTypes.object,
+ refresh: PropTypes.bool.isRequired,
onSearchStateChange: PropTypes.func,
onSearchParameters: PropTypes.func,
resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};
+ static defaultProps = {
+ refresh: false,
+ };
+
constructor(props) {
super();
this.client =
@@ -60,6 +65,7 @@ export default function createInstantSearch(defaultAlgoliaClient, root) {
onSearchParameters={this.props.onSearchParameters}
root={root}
algoliaClient={this.client}
+ refresh={this.props.refresh}
resultsState={this.props.resultsState}
>
{this.props.children}
diff --git a/packages/react-instantsearch/src/core/createInstantSearchManager.js b/packages/react-instantsearch/src/core/createInstantSearchManager.js
index 6fcc7d0482..5b8789d3b6 100644
--- a/packages/react-instantsearch/src/core/createInstantSearchManager.js
+++ b/packages/react-instantsearch/src/core/createInstantSearchManager.js
@@ -57,6 +57,11 @@ export default function createInstantSearchManager({
search();
}
+ function clearCache() {
+ helper.clearCache();
+ search();
+ }
+
function getMetadata(state) {
return widgetsManager
.getWidgets()
@@ -292,6 +297,7 @@ export default function createInstantSearchManager({
onSearchForFacetValues,
updateClient,
updateIndex,
+ clearCache,
skipSearch,
};
}
diff --git a/stories/RefreshCache.stories.js b/stories/RefreshCache.stories.js
new file mode 100644
index 0000000000..9588562f4b
--- /dev/null
+++ b/stories/RefreshCache.stories.js
@@ -0,0 +1,130 @@
+import React, { Component } from 'react';
+import { storiesOf } from '@storybook/react';
+import { InstantSearch, SearchBox } from '../packages/react-instantsearch/dom';
+import { CustomHits } from './util';
+
+const stories = storiesOf('RefreshCache', module);
+
+class AppWithRefresh extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ refresh: false,
+ };
+ }
+
+ refresh = () => {
+ this.setState(prevState => ({
+ refresh: !prevState.refresh,
+ }));
+ };
+
+ onSearchStateChange = () => {
+ this.setState({ refresh: false });
+ };
+
+ render() {
+ const displayRefresh = `${this.state.refresh}`;
+ return (
+
+
+
+ Feature: Refresh cache
+
+
+ Adding the refresh prop to your InstantSearch component gives you
+ the possibility to refresh the cache.
+
+
+
+ How to test it?
+
+
+ By default, the 'refresh' prop is disabled. You will need
+ to open your network tab in the developer tools.
+
+
+ Type a query in the SearchBox (for instance 'clock').
+ You should see 5 requests to Algolia (one per letter)
+
+
+ Type 'clock' again, you will see that no additional
+ query is made since the results are retrieved from the cache
+
+
+ Make sure the SearchBox is empty, click on the 'Refresh
+ cache' button (you should see that Refresh set to true in
+ the info box below the SearchBox)
+
+
+ Type your previous query again: the cache has been cleared and
+ you will see new requests made to Algolia
+
+
+
+
+
+
+
+ Refresh cache
+
+
+ Refresh is set to: {displayRefresh}
+
+
+
+
+ );
+ }
+}
+
+stories.add('with a refresh button', () => );
diff --git a/stories/util.js b/stories/util.js
index f7a6334f2f..945d6f5e59 100644
--- a/stories/util.js
+++ b/stories/util.js
@@ -193,4 +193,4 @@ const displayName = element => {
const filterProps = ['linkedStoryGroup', 'hasPlayground'];
-export { displayName, filterProps, Wrap, WrapWithHits };
+export { CustomHits, displayName, filterProps, Wrap, WrapWithHits };