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

Commit 9870e85

Browse files
authored
feat(StateResults): give access to search parameters (#627)
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> ```
1 parent 076e5d4 commit 9870e85

File tree

7 files changed

+389
-80
lines changed

7 files changed

+389
-80
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
"bundlesize": [
112112
{
113113
"path": "./dist/vue-instantsearch.js",
114-
"maxSize": "60.50 kB"
114+
"maxSize": "60.60 kB"
115115
},
116116
{
117117
"path": "./dist/vue-instantsearch.esm.js",

src/components/StateResults.vue

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,40 @@
11
<template>
22
<div
33
:class="suit()"
4-
v-if="state && state.results"
4+
v-if="state && state.state && state.results"
55
>
6-
<slot v-bind="state.results">
7-
<p>Use this component to have a different layout based on a certain state.</p>
8-
<p>Fill in the slot, and get access to the following things on the <code>slot-scope</code>:</p>
9-
<pre>{{ Object.keys(state.results) }}</pre>
6+
<slot v-bind="stateResults">
7+
<p>
8+
Use this component to have a different layout based on a certain state.
9+
</p>
10+
<p>
11+
Fill in the slot, and get access to the following things on the
12+
<code>slot-scope</code>:
13+
</p>
14+
<pre>results: {{ Object.keys(state.results) }}</pre>
15+
<pre>state: {{ Object.keys(state.state) }}</pre>
1016
</slot>
1117
</div>
1218
</template>
1319

1420
<script>
1521
import { createSuitMixin } from '../mixins/suit';
1622
import { createWidgetMixin } from '../mixins/widget';
17-
18-
const connectStateResults = (renderFn, unmountFn) => (widgetParams = {}) => ({
19-
init({ instantSearchInstance }) {
20-
renderFn(
21-
{
22-
results: undefined,
23-
instantSearchInstance,
24-
widgetParams,
25-
},
26-
true
27-
);
28-
},
29-
30-
render({ results, instantSearchInstance }) {
31-
const resultsCopy = Object.assign({}, results);
32-
// delete internal state, not to be exposed
33-
delete resultsCopy._state;
34-
renderFn(
35-
{
36-
results: resultsCopy,
37-
instantSearchInstance,
38-
widgetParams,
39-
},
40-
false
41-
);
42-
},
43-
44-
dispose() {
45-
unmountFn();
46-
},
47-
});
23+
import { _objectSpread } from '../util/polyfills';
24+
import connectStateResults from '../connectors/connectStateResults';
4825
4926
export default {
5027
name: 'AisStateResults',
5128
mixins: [
5229
createWidgetMixin({ connector: connectStateResults }),
5330
createSuitMixin({ name: 'StateResults' }),
5431
],
32+
computed: {
33+
stateResults() {
34+
// @MAJOR: replace v-bind="stateResults" with :state="state.state" :results="state.results"
35+
const { state, results } = this.state;
36+
return _objectSpread({}, results, { results, state });
37+
},
38+
},
5539
};
5640
</script>

src/components/__tests__/StateResults.js

Lines changed: 167 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ jest.mock('../../mixins/widget');
66
it('renders explanation if no slot is used', () => {
77
__setState({
88
results: {
9-
query: 'q',
9+
query: 'this is the quer',
1010
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
1111
page: 1,
1212
},
13+
state: {
14+
query: 'this is the query',
15+
},
1316
});
1417
const wrapper = mount(StateResults);
1518
expect(wrapper.html()).toMatchSnapshot();
@@ -21,37 +24,91 @@ it("doesn't render if no results", () => {
2124
expect(wrapper.html()).toBeUndefined();
2225
});
2326

24-
it('gives results to default slot', () => {
27+
it('gives state & results to default slot', () => {
2528
const results = {
2629
query: 'q',
2730
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
2831
page: 1,
2932
};
33+
const state = {
34+
query: 'something',
35+
disjunctiveFacetsRefinements: {},
36+
page: 1,
37+
};
3038

3139
__setState({
40+
state,
3241
results,
3342
});
3443

3544
mount(StateResults, {
3645
scopedSlots: {
37-
default: props => expect(props).toEqual(results),
46+
default: props => {
47+
expect(props).toEqual(expect.objectContaining(results));
48+
expect(props.results).toEqual(results);
49+
expect(props.state).toEqual(state);
50+
},
3851
},
3952
});
4053
});
4154

42-
it('allows default slot to render whatever they want (truthy query)', () => {
55+
it('allows default slot to render whatever they want', () => {
56+
const results = {
57+
query: 'hi',
58+
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
59+
page: 1,
60+
};
61+
const state = {
62+
query: 'hi!',
63+
};
4364
__setState({
44-
results: {
45-
query: 'q',
46-
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
47-
page: 1,
65+
state,
66+
results,
67+
});
68+
69+
const wrapper = mount(StateResults, {
70+
scopedSlots: {
71+
default: `
72+
<template slot-scope="{ state: { query }, results: { page } }">
73+
<p v-if="query">
74+
Query is here, page is {{ page }}
75+
</p>
76+
<p v-else>
77+
There's no query
78+
</p>
79+
</template>`,
4880
},
4981
});
5082

83+
expect(wrapper.html()).toMatchInlineSnapshot(`
84+
85+
<div class="ais-StateResults">
86+
<p>
87+
Query is here, page is 1
88+
</p>
89+
</div>
90+
91+
`);
92+
});
93+
94+
it('allows default slot to render whatever they want (truthy query)', () => {
95+
const results = {
96+
query: 'hi',
97+
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
98+
page: 1,
99+
};
100+
const state = {
101+
query: 'hi!',
102+
};
103+
__setState({
104+
state,
105+
results,
106+
});
107+
51108
const wrapper = mount(StateResults, {
52109
scopedSlots: {
53110
default: `
54-
<template slot-scope="{ query }">
111+
<template slot-scope="{ results: { query } }">
55112
<p v-if="query">
56113
Query is here
57114
</p>
@@ -62,22 +119,35 @@ it('allows default slot to render whatever they want (truthy query)', () => {
62119
},
63120
});
64121

65-
expect(wrapper.html()).toMatchSnapshot();
122+
expect(wrapper.html()).toMatchInlineSnapshot(`
123+
124+
<div class="ais-StateResults">
125+
<p>
126+
Query is here
127+
</p>
128+
</div>
129+
130+
`);
66131
});
67132

68133
it('allows default slot to render whatever they want (falsy query)', () => {
134+
const results = {
135+
query: '',
136+
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
137+
page: 1,
138+
};
139+
const state = {
140+
query: 'hi!',
141+
};
69142
__setState({
70-
results: {
71-
query: '',
72-
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
73-
page: 1,
74-
},
143+
state,
144+
results,
75145
});
76146

77147
const wrapper = mount(StateResults, {
78148
scopedSlots: {
79149
default: `
80-
<template slot-scope="{ query }">
150+
<template slot-scope="{ results: { query } }">
81151
<p v-if="query">
82152
Query is here
83153
</p>
@@ -88,5 +158,85 @@ it('allows default slot to render whatever they want (falsy query)', () => {
88158
},
89159
});
90160

91-
expect(wrapper.html()).toMatchSnapshot();
161+
expect(wrapper.html()).toMatchInlineSnapshot(`
162+
163+
<div class="ais-StateResults">
164+
<p>
165+
There's no query
166+
</p>
167+
</div>
168+
169+
`);
170+
});
171+
172+
describe('legacy spread props', () => {
173+
it('allows default slot to render whatever they want (truthy query)', () => {
174+
__setState({
175+
results: {
176+
query: 'q',
177+
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
178+
page: 1,
179+
},
180+
state: {},
181+
});
182+
183+
const wrapper = mount(StateResults, {
184+
scopedSlots: {
185+
default: `
186+
<template slot-scope="{ query }">
187+
<p v-if="query">
188+
Query is here
189+
</p>
190+
<p v-else>
191+
There's no query
192+
</p>
193+
</template>`,
194+
},
195+
});
196+
197+
expect(wrapper.html()).toMatchInlineSnapshot(`
198+
199+
<div class="ais-StateResults">
200+
<p>
201+
Query is here
202+
</p>
203+
</div>
204+
205+
`);
206+
});
207+
208+
it('allows default slot to render whatever they want (falsy query)', () => {
209+
__setState({
210+
results: {
211+
query: '',
212+
hits: [{ objectID: '1', name: 'one' }, { objectID: '2', name: 'two' }],
213+
page: 1,
214+
},
215+
state: {},
216+
});
217+
218+
const wrapper = mount(StateResults, {
219+
scopedSlots: {
220+
default: `
221+
<template slot-scope="{ query }">
222+
<p v-if="query">
223+
Query is here
224+
</p>
225+
<p v-else>
226+
There's no query
227+
</p>
228+
</template>`,
229+
},
230+
});
231+
232+
expect(wrapper.html()).toMatchInlineSnapshot(`
233+
234+
<div class="ais-StateResults">
235+
<p>
236+
There's no query
237+
</p>
238+
</div>
239+
240+
`);
241+
});
92242
});

src/components/__tests__/__snapshots__/StateResults.js.snap

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,5 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`allows default slot to render whatever they want (falsy query) 1`] = `
4-
5-
<div class="ais-StateResults">
6-
<p>
7-
There's no query
8-
</p>
9-
</div>
10-
11-
`;
12-
13-
exports[`allows default slot to render whatever they want (truthy query) 1`] = `
14-
15-
<div class="ais-StateResults">
16-
<p>
17-
Query is here
18-
</p>
19-
</div>
20-
21-
`;
22-
233
exports[`renders explanation if no slot is used 1`] = `
244
255
<div class="ais-StateResults">
@@ -34,10 +14,15 @@ exports[`renders explanation if no slot is used 1`] = `
3414
:
3515
</p>
3616
<pre>
37-
[
17+
results: [
3818
"query",
3919
"hits",
4020
"page"
21+
]
22+
</pre>
23+
<pre>
24+
state: [
25+
"query"
4126
]
4227
</pre>
4328
</div>

0 commit comments

Comments
 (0)