From 94c484e80d2aaed86a604658eea5d493f50b563a Mon Sep 17 00:00:00 2001 From: Marie-Laure Thuret Date: Wed, 12 Jul 2017 20:00:47 +0200 Subject: [PATCH] docs: add algolia-react-instantsearch example (#2544) * docs: add algolia-react-instantsearch example * fix: style --- .../.gitignore | 19 ++++ .../README.md | 34 +++++++ .../components/app.js | 86 ++++++++++++++++++ .../components/head.js | 48 ++++++++++ .../components/index.js | 3 + .../components/instantsearch.js | 5 + .../next.config.js | 19 ++++ .../package.json | 19 ++++ .../pages/index.js | 73 +++++++++++++++ .../static/favicon.ico | Bin 0 -> 15086 bytes .../static/instantsearch.css | 48 ++++++++++ 11 files changed, 354 insertions(+) create mode 100644 examples/with-algolia-react-instantsearch/.gitignore create mode 100644 examples/with-algolia-react-instantsearch/README.md create mode 100644 examples/with-algolia-react-instantsearch/components/app.js create mode 100644 examples/with-algolia-react-instantsearch/components/head.js create mode 100644 examples/with-algolia-react-instantsearch/components/index.js create mode 100644 examples/with-algolia-react-instantsearch/components/instantsearch.js create mode 100644 examples/with-algolia-react-instantsearch/next.config.js create mode 100644 examples/with-algolia-react-instantsearch/package.json create mode 100644 examples/with-algolia-react-instantsearch/pages/index.js create mode 100644 examples/with-algolia-react-instantsearch/static/favicon.ico create mode 100644 examples/with-algolia-react-instantsearch/static/instantsearch.css diff --git a/examples/with-algolia-react-instantsearch/.gitignore b/examples/with-algolia-react-instantsearch/.gitignore new file mode 100644 index 00000000..e2ff6828 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/.gitignore @@ -0,0 +1,19 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +# testing +/coverage + +# production +/build +/dist +/.next + +# misc +.DS_Store +.env +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/examples/with-algolia-react-instantsearch/README.md b/examples/with-algolia-react-instantsearch/README.md new file mode 100644 index 00000000..ef25a499 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/README.md @@ -0,0 +1,34 @@ +[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-algolia-react-instantsearch) + +# With Algolia React InstantSearch example + +## How to use + +Download the example [or clone the repo](https://github.com/zeit/next.js): + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-algolia-react-instantsearch +cd with-algolia-react-instantsearch +``` + +Set up Algolia: +- create an [algolia](https://www.algolia.com/) account or use this already [configured index](https://community.algolia.com/react-instantsearch/Getting_started.html#before-we-start) +- update the appId, apikey and indexName you want to search on in components/app.js + +Install it and run: + +```bash +npm install +npm run dev +``` + +Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)) + +```bash +now +``` + +## The idea behind the example +The goal of this example is to illustrate how you can use [Algolia React InstantSearch](https://community.algolia.com/react-instantsearch/) to perform +your search with a Server-rendered application developed with Next.js. It also illustrates how you +can keep in sync the Url with the search. diff --git a/examples/with-algolia-react-instantsearch/components/app.js b/examples/with-algolia-react-instantsearch/components/app.js new file mode 100644 index 00000000..3f68a58c --- /dev/null +++ b/examples/with-algolia-react-instantsearch/components/app.js @@ -0,0 +1,86 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { + RefinementList, + SearchBox, + Hits, + Configure, + Highlight, + Pagination +} from 'react-instantsearch/dom' +import { InstantSearch } from './instantsearch' + +const HitComponent = ({ hit }) => +
+
+
+ +
+
+
+
+ + + {' '}- ${hit.price} + + + {' '}- {hit.rating} stars + +
+
+ +
+
+ +
+
+
+ +HitComponent.propTypes = { + hit: PropTypes.object +} + +export default class extends React.Component { + static propTypes = { + searchState: PropTypes.object, + resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), + onSearchStateChange: PropTypes.func + }; + + render () { + return ( + + +
+

React InstantSearch + Next.Js

+ +
+ + + + + + + + + +
+ ) + } +} diff --git a/examples/with-algolia-react-instantsearch/components/head.js b/examples/with-algolia-react-instantsearch/components/head.js new file mode 100644 index 00000000..0737bb58 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/components/head.js @@ -0,0 +1,48 @@ +import NextHead from 'next/head' +import { string } from 'prop-types' +import React from 'react' + +const defaultDescription = '' +const defaultOGURL = '' +const defaultOGImage = '' + +export const Head = props => + + + {props.title || ''} + + + + + + + + + + + + + + + + + + + +Head.propTypes = { + title: string, + description: string, + url: string, + ogImage: string +} + +export default Head diff --git a/examples/with-algolia-react-instantsearch/components/index.js b/examples/with-algolia-react-instantsearch/components/index.js new file mode 100644 index 00000000..ce4b600e --- /dev/null +++ b/examples/with-algolia-react-instantsearch/components/index.js @@ -0,0 +1,3 @@ +export * from './head' +export { default as App } from './app' +export { findResultsState } from './instantsearch' diff --git a/examples/with-algolia-react-instantsearch/components/instantsearch.js b/examples/with-algolia-react-instantsearch/components/instantsearch.js new file mode 100644 index 00000000..ee62326e --- /dev/null +++ b/examples/with-algolia-react-instantsearch/components/instantsearch.js @@ -0,0 +1,5 @@ +import { createInstantSearch } from 'react-instantsearch/server' + +const { InstantSearch, findResultsState } = createInstantSearch() + +export { InstantSearch, findResultsState } diff --git a/examples/with-algolia-react-instantsearch/next.config.js b/examples/with-algolia-react-instantsearch/next.config.js new file mode 100644 index 00000000..4d1883f0 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/next.config.js @@ -0,0 +1,19 @@ +/* eslint-disable import/no-commonjs */ + +module.exports = { + webpack: config => { + // Fixes npm packages that depend on `fs` module + config.node = { + fs: 'empty' + } + config.module.rules.push({ + test: /\.css$/, + loader: ['style-loader', 'css-loader'] + }) + if (config.resolve.alias) { + delete config.resolve.alias.react + delete config.resolve.alias['react-dom'] + } + return config + } +} diff --git a/examples/with-algolia-react-instantsearch/package.json b/examples/with-algolia-react-instantsearch/package.json new file mode 100644 index 00000000..b6e219f5 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/package.json @@ -0,0 +1,19 @@ +{ + "name": "create-next-example-app", + "scripts": { + "dev": "next", + "build": "NODE_ENV=development next build", + "start": "next start" + }, + "dependencies": { + "css-loader": "^0.28.1", + "next": "^2.4.7", + "prop-types": "^15.5.10", + "qs": "^6.4.0", + "react": "^15.5.4", + "react-dom": "^15.5.4", + "react-instantsearch": "beta", + "react-instantsearch-theme-algolia": "beta", + "style-loader": "^0.17.0" + } +} diff --git a/examples/with-algolia-react-instantsearch/pages/index.js b/examples/with-algolia-react-instantsearch/pages/index.js new file mode 100644 index 00000000..e5690971 --- /dev/null +++ b/examples/with-algolia-react-instantsearch/pages/index.js @@ -0,0 +1,73 @@ +import { Head, App, findResultsState } from '../components' +import React from 'react' +import PropTypes from 'prop-types' +import Router from 'next/router' +import qs from 'qs' + +const updateAfter = 700 + +const searchStateToUrl = searchState => + searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : '' + +export default class extends React.Component { + static propTypes = { + resultsState: PropTypes.object, + searchState: PropTypes.object + }; + + constructor (props) { + super(props) + this.onSearchStateChange = this.onSearchStateChange.bind(this) + } + + /* + nextjs params.query doesn't handle nested objects + once it does, params.query could be used directly here, but also inside the constructor + to initialize the searchState. + */ + static async getInitialProps (params) { + const searchState = qs.parse( + params.asPath.substring(params.asPath.indexOf('?') + 1) + ) + const resultsState = await findResultsState(App, { searchState }) + return { resultsState, searchState } + } + + onSearchStateChange = searchState => { + clearTimeout(this.debouncedSetState) + this.debouncedSetState = setTimeout(() => { + const href = searchStateToUrl(searchState) + Router.push(href, href, { + shallow: true + }) + }, updateAfter) + this.setState({ searchState }) + }; + + componentDidMount () { + this.setState({ searchState: qs.parse(window.location.search.slice(1)) }) + } + + componentWillReceiveProps () { + this.setState({ searchState: qs.parse(window.location.search.slice(1)) }) + } + + render () { + return ( +
+ +
+ +
+
+ ) + } +} diff --git a/examples/with-algolia-react-instantsearch/static/favicon.ico b/examples/with-algolia-react-instantsearch/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a GIT binary patch literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*-