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

Commit 391b9f4

Browse files
chore(examples): update next example to Next 12 (#3438)
* chore(examples): update next example to Next 12 see https://github.com/algolia/react-instantsearch/discussions/3434 * Update examples/next/components/app.js Co-authored-by: François Chalifour <[email protected]> * Apply suggestions from code review Co-authored-by: François Chalifour <[email protected]> * simplify further * document the simpler form * fix types Co-authored-by: François Chalifour <[email protected]>
1 parent 38f9680 commit 391b9f4

File tree

10 files changed

+257
-758
lines changed

10 files changed

+257
-758
lines changed

examples/hooks-next/pages/index.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Head from 'next/head';
2+
import { GetServerSideProps } from 'next';
23
import algoliasearch from 'algoliasearch/lite';
34
import { Hit as AlgoliaHit } from 'instantsearch.js';
45
import {
@@ -82,15 +83,16 @@ function FallbackComponent({ attribute }: { attribute: string }) {
8283
);
8384
}
8485

85-
export async function getServerSideProps({ req }) {
86-
const protocol = req.headers.referer?.split('://')[0] || 'https';
87-
const url = `${protocol}://${req.headers.host}${req.url}`;
88-
const serverState = await getServerState(<HomePage url={url} />);
86+
export const getServerSideProps: GetServerSideProps<HomePageProps> =
87+
async function getServerSideProps({ req }) {
88+
const protocol = req.headers.referer?.split('://')[0] || 'https';
89+
const url = `${protocol}://${req.headers.host}${req.url}`;
90+
const serverState = await getServerState(<HomePage url={url} />);
8991

90-
return {
91-
props: {
92-
serverState,
93-
url,
94-
},
92+
return {
93+
props: {
94+
serverState,
95+
url,
96+
},
97+
};
9598
};
96-
}

examples/next/.babelrc

Lines changed: 0 additions & 26 deletions
This file was deleted.

examples/next/components/app.js

Lines changed: 28 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from 'react';
2-
import PropTypes from 'prop-types';
32
import {
43
RefinementList,
54
SearchBox,
@@ -33,56 +32,32 @@ const HitComponent = ({ hit }) => (
3332
</div>
3433
);
3534

36-
HitComponent.propTypes = {
37-
hit: PropTypes.object,
38-
};
39-
40-
export default class extends React.Component {
41-
static propTypes = {
42-
searchState: PropTypes.object,
43-
resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
44-
onSearchStateChange: PropTypes.func,
45-
createURL: PropTypes.func,
46-
indexName: PropTypes.string,
47-
searchClient: PropTypes.object,
48-
};
49-
50-
render() {
51-
return (
52-
<InstantSearch
53-
searchClient={this.props.searchClient}
54-
resultsState={this.props.resultsState}
55-
onSearchStateChange={this.props.onSearchStateChange}
56-
searchState={this.props.searchState}
57-
createURL={this.props.createURL}
58-
indexName={this.props.indexName}
59-
onSearchParameters={this.props.onSearchParameters}
60-
{...this.props}
61-
>
62-
<Configure hitsPerPage={12} />
63-
<header>
64-
<h1>React InstantSearch + Next.Js</h1>
65-
<SearchBox />
66-
</header>
67-
<main>
68-
<div className="menu">
69-
<RefinementList attribute="categories" />
70-
</div>
71-
<div className="results">
72-
<Hits hitComponent={HitComponent} />
73-
</div>
74-
</main>
75-
<footer>
76-
<Pagination />
77-
<div>
78-
See{' '}
79-
<a href="https://github.com/algolia/react-instantsearch/tree/master/examples/next">
80-
source code
81-
</a>{' '}
82-
on github
83-
</div>
84-
</footer>
85-
</InstantSearch>
86-
);
87-
}
35+
export function App(props) {
36+
return (
37+
<InstantSearch {...props}>
38+
<Configure hitsPerPage={12} />
39+
<header>
40+
<h1>React InstantSearch + Next.js</h1>
41+
<SearchBox />
42+
</header>
43+
<main>
44+
<div className="menu">
45+
<RefinementList attribute="categories" />
46+
</div>
47+
<div className="results">
48+
<Hits hitComponent={HitComponent} />
49+
</div>
50+
</main>
51+
<footer>
52+
<Pagination />
53+
<div>
54+
See{' '}
55+
<a href="https://github.com/algolia/react-instantsearch/tree/master/examples/next">
56+
source code
57+
</a>{' '}
58+
on GitHub
59+
</div>
60+
</footer>
61+
</InstantSearch>
62+
);
8863
}

examples/next/components/head.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import NextHead from 'next/head';
2-
import { string } from 'prop-types';
32
import React from 'react';
43

54
const defaultDescription = '';
@@ -34,12 +33,3 @@ export const Head = (props) => (
3433
<link rel="stylesheet" href="instantsearch.css" />
3534
</NextHead>
3635
);
37-
38-
Head.propTypes = {
39-
title: string,
40-
description: string,
41-
url: string,
42-
ogImage: string,
43-
};
44-
45-
export default Head;

examples/next/components/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './head';
2-
export { default as App } from './app';
2+
export * from './app';

examples/next/next.config.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

examples/next/package.json

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,24 @@
88
"build": "next build",
99
"start": "next start"
1010
},
11-
"devDependencies": {
12-
"babel-core": "7.0.0-bridge.0",
13-
"babel-jest": "23.6.0",
14-
"css-loader": "3.2.0",
15-
"style-loader": "1.0.0"
11+
"jest": {
12+
"transform": {
13+
"^.+\\.(js|jsx|ts|tsx)$": [
14+
"babel-jest",
15+
{
16+
"presets": [
17+
"next/babel"
18+
]
19+
}
20+
]
21+
}
1622
},
1723
"dependencies": {
1824
"algoliasearch": "4.11.0",
19-
"next": "9.1.1",
20-
"prop-types": "15.6.2",
25+
"next": "12.1.5",
2126
"qs": "6.8.0",
2227
"react": "17.0.2",
2328
"react-dom": "17.0.2",
24-
"react-fast-compare": "3.0.1",
2529
"react-instantsearch-dom": "6.23.3"
2630
}
2731
}

examples/next/pages/index.js

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import isEqual from 'react-fast-compare';
21
import React from 'react';
3-
import PropTypes from 'prop-types';
4-
import { withRouter } from 'next/router';
2+
import { useRouter } from 'next/router';
53
import qs from 'qs';
64
import algoliasearch from 'algoliasearch/lite';
75
import { findResultsState } from 'react-instantsearch-dom/server';
@@ -27,70 +25,54 @@ const DEFAULT_PROPS = {
2725
indexName: 'instant_search',
2826
};
2927

30-
class Page extends React.Component {
31-
static propTypes = {
32-
router: PropTypes.object.isRequired,
33-
resultsState: PropTypes.object,
34-
searchState: PropTypes.object,
35-
};
36-
37-
state = {
38-
searchState: this.props.searchState,
39-
lastRouter: this.props.router,
40-
};
41-
42-
static async getInitialProps({ asPath }) {
43-
const searchState = pathToSearchState(asPath);
44-
const resultsState = await findResultsState(App, {
45-
...DEFAULT_PROPS,
46-
searchState,
47-
});
48-
49-
return {
50-
resultsState,
51-
searchState,
52-
};
53-
}
28+
export default function Page(props) {
29+
const [searchState, setSearchState] = React.useState(props.searchState);
30+
const router = useRouter();
31+
const debouncedSetState = React.useRef();
5432

55-
static getDerivedStateFromProps(props, state) {
56-
if (!isEqual(state.lastRouter, props.router)) {
57-
return {
58-
searchState: pathToSearchState(props.router.asPath),
59-
lastRouter: props.router,
60-
};
33+
React.useEffect(() => {
34+
if (router) {
35+
router.beforePopState(({ url }) => {
36+
setSearchState(pathToSearchState(url));
37+
});
6138
}
39+
}, [router]);
40+
41+
return (
42+
<div>
43+
<Head title="Home" />
44+
<App
45+
{...DEFAULT_PROPS}
46+
searchState={searchState}
47+
resultsState={props.resultsState}
48+
onSearchStateChange={(nextSearchState) => {
49+
clearTimeout(debouncedSetState.current);
50+
51+
debouncedSetState.current = setTimeout(() => {
52+
const href = searchStateToURL(nextSearchState);
53+
54+
router.push(href, href, { shallow: true });
55+
}, updateAfter);
56+
57+
setSearchState(nextSearchState);
58+
}}
59+
createURL={createURL}
60+
/>
61+
</div>
62+
);
63+
}
6264

63-
return null;
64-
}
65-
66-
onSearchStateChange = (searchState) => {
67-
clearTimeout(this.debouncedSetState);
68-
69-
this.debouncedSetState = setTimeout(() => {
70-
const href = searchStateToURL(searchState);
71-
72-
this.props.router.push(href, href, {
73-
shallow: true,
74-
});
75-
}, updateAfter);
65+
export async function getServerSideProps({ resolvedUrl }) {
66+
const searchState = pathToSearchState(resolvedUrl);
67+
const resultsState = await findResultsState(App, {
68+
...DEFAULT_PROPS,
69+
searchState,
70+
});
7671

77-
this.setState({ searchState });
72+
return {
73+
props: {
74+
resultsState: JSON.parse(JSON.stringify(resultsState)),
75+
searchState,
76+
},
7877
};
79-
80-
render() {
81-
return (
82-
<div>
83-
<Head title="Home" />
84-
<App
85-
{...DEFAULT_PROPS}
86-
searchState={this.state.searchState}
87-
resultsState={this.props.resultsState}
88-
onSearchStateChange={this.onSearchStateChange}
89-
createURL={createURL}
90-
/>
91-
</div>
92-
);
93-
}
9478
}
95-
96-
export default withRouter(Page);

global.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
11
declare const __DEV__: boolean;
2+
3+
declare namespace NodeJS {
4+
// override the type set by Next (in examples), which sets NODE_ENV to readonly globally
5+
interface ProcessEnv {
6+
NODE_ENV: 'development' | 'production' | 'test';
7+
}
8+
}

0 commit comments

Comments
 (0)