Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
feat(StateResults): give access to search parameters (#627)
Browse files Browse the repository at this point in the history
This changes the internal `connectStateResults` connector so that it exposes the state too, but without the methods.

This is not a breaking change in the widget, so should be straightforward to migrate to the new usage:

```diff
<ais-state-results>
- <template slot-scope="{ query, hits }">
+ <template slot-scope="{ results: { query, hits } }">
  </template>
</ais-state-results>
```

It allows you to read from the state as well, avoiding race conditions if for example hiding hits based on the query.

```diff
<ais-state-results>
- <div slot-scope="{ query }">
+ <div slot-scope="{ state: { query } }">
    <ais-hits v-if="query" />
  </div>
</ais-state-results>
```
  • Loading branch information
Haroenv authored Jan 10, 2020
1 parent 076e5d4 commit 9870e85
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 80 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
"bundlesize": [
{
"path": "./dist/vue-instantsearch.js",
"maxSize": "60.50 kB"
"maxSize": "60.60 kB"
},
{
"path": "./dist/vue-instantsearch.esm.js",
Expand Down
56 changes: 20 additions & 36 deletions src/components/StateResults.vue
Original file line number Diff line number Diff line change
@@ -1,56 +1,40 @@
<template>
<div
:class="suit()"
v-if="state && state.results"
v-if="state && state.state && state.results"
>
<slot v-bind="state.results">
<p>Use this component to have a different layout based on a certain state.</p>
<p>Fill in the slot, and get access to the following things on the <code>slot-scope</code>:</p>
<pre>{{ Object.keys(state.results) }}</pre>
<slot v-bind="stateResults">
<p>
Use this component to have a different layout based on a certain state.
</p>
<p>
Fill in the slot, and get access to the following things on the
<code>slot-scope</code>:
</p>
<pre>results: {{ Object.keys(state.results) }}</pre>
<pre>state: {{ Object.keys(state.state) }}</pre>
</slot>
</div>
</template>

<script>
import { createSuitMixin } from '../mixins/suit';
import { createWidgetMixin } from '../mixins/widget';
const connectStateResults = (renderFn, unmountFn) => (widgetParams = {}) => ({
init({ instantSearchInstance }) {
renderFn(
{
results: undefined,
instantSearchInstance,
widgetParams,
},
true
);
},
render({ results, instantSearchInstance }) {
const resultsCopy = Object.assign({}, results);
// delete internal state, not to be exposed
delete resultsCopy._state;
renderFn(
{
results: resultsCopy,
instantSearchInstance,
widgetParams,
},
false
);
},
dispose() {
unmountFn();
},
});
import { _objectSpread } from '../util/polyfills';
import connectStateResults from '../connectors/connectStateResults';
export default {
name: 'AisStateResults',
mixins: [
createWidgetMixin({ connector: connectStateResults }),
createSuitMixin({ name: 'StateResults' }),
],
computed: {
stateResults() {
// @MAJOR: replace v-bind="stateResults" with :state="state.state" :results="state.results"
const { state, results } = this.state;
return _objectSpread({}, results, { results, state });
},
},
};
</script>
184 changes: 167 additions & 17 deletions src/components/__tests__/StateResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ jest.mock('../../mixins/widget');
it('renders explanation if no slot is used', () => {
__setState({
results: {
query: 'q',
query: 'this is the quer',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
},
state: {
query: 'this is the query',
},
});
const wrapper = mount(StateResults);
expect(wrapper.html()).toMatchSnapshot();
Expand All @@ -21,37 +24,91 @@ it("doesn't render if no results", () => {
expect(wrapper.html()).toBeUndefined();
});

it('gives results to default slot', () => {
it('gives state & results to default slot', () => {
const results = {
query: 'q',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
};
const state = {
query: 'something',
disjunctiveFacetsRefinements: {},
page: 1,
};

__setState({
state,
results,
});

mount(StateResults, {
scopedSlots: {
default: props => expect(props).toEqual(results),
default: props => {
expect(props).toEqual(expect.objectContaining(results));
expect(props.results).toEqual(results);
expect(props.state).toEqual(state);
},
},
});
});

it('allows default slot to render whatever they want (truthy query)', () => {
it('allows default slot to render whatever they want', () => {
const results = {
query: 'hi',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
};
const state = {
query: 'hi!',
};
__setState({
results: {
query: 'q',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
state,
results,
});

const wrapper = mount(StateResults, {
scopedSlots: {
default: `
<template slot-scope="{ state: { query }, results: { page } }">
<p v-if="query">
Query is here, page is {{ page }}
</p>
<p v-else>
There's no query
</p>
</template>`,
},
});

expect(wrapper.html()).toMatchInlineSnapshot(`
<div class="ais-StateResults">
<p>
Query is here, page is 1
</p>
</div>
`);
});

it('allows default slot to render whatever they want (truthy query)', () => {
const results = {
query: 'hi',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
};
const state = {
query: 'hi!',
};
__setState({
state,
results,
});

const wrapper = mount(StateResults, {
scopedSlots: {
default: `
<template slot-scope="{ query }">
<template slot-scope="{ results: { query } }">
<p v-if="query">
Query is here
</p>
Expand All @@ -62,22 +119,35 @@ it('allows default slot to render whatever they want (truthy query)', () => {
},
});

expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.html()).toMatchInlineSnapshot(`
<div class="ais-StateResults">
<p>
Query is here
</p>
</div>
`);
});

it('allows default slot to render whatever they want (falsy query)', () => {
const results = {
query: '',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
};
const state = {
query: 'hi!',
};
__setState({
results: {
query: '',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
},
state,
results,
});

const wrapper = mount(StateResults, {
scopedSlots: {
default: `
<template slot-scope="{ query }">
<template slot-scope="{ results: { query } }">
<p v-if="query">
Query is here
</p>
Expand All @@ -88,5 +158,85 @@ it('allows default slot to render whatever they want (falsy query)', () => {
},
});

expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.html()).toMatchInlineSnapshot(`
<div class="ais-StateResults">
<p>
There's no query
</p>
</div>
`);
});

describe('legacy spread props', () => {
it('allows default slot to render whatever they want (truthy query)', () => {
__setState({
results: {
query: 'q',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
},
state: {},
});

const wrapper = mount(StateResults, {
scopedSlots: {
default: `
<template slot-scope="{ query }">
<p v-if="query">
Query is here
</p>
<p v-else>
There's no query
</p>
</template>`,
},
});

expect(wrapper.html()).toMatchInlineSnapshot(`
<div class="ais-StateResults">
<p>
Query is here
</p>
</div>
`);
});

it('allows default slot to render whatever they want (falsy query)', () => {
__setState({
results: {
query: '',
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
page: 1,
},
state: {},
});

const wrapper = mount(StateResults, {
scopedSlots: {
default: `
<template slot-scope="{ query }">
<p v-if="query">
Query is here
</p>
<p v-else>
There's no query
</p>
</template>`,
},
});

expect(wrapper.html()).toMatchInlineSnapshot(`
<div class="ais-StateResults">
<p>
There's no query
</p>
</div>
`);
});
});
27 changes: 6 additions & 21 deletions src/components/__tests__/__snapshots__/StateResults.js.snap
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`allows default slot to render whatever they want (falsy query) 1`] = `
<div class="ais-StateResults">
<p>
There's no query
</p>
</div>
`;

exports[`allows default slot to render whatever they want (truthy query) 1`] = `
<div class="ais-StateResults">
<p>
Query is here
</p>
</div>
`;

exports[`renders explanation if no slot is used 1`] = `
<div class="ais-StateResults">
Expand All @@ -34,10 +14,15 @@ exports[`renders explanation if no slot is used 1`] = `
:
</p>
<pre>
[
results: [
"query",
"hits",
"page"
]
</pre>
<pre>
state: [
"query"
]
</pre>
</div>
Expand Down
Loading

0 comments on commit 9870e85

Please sign in to comment.