1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

docs: add algolia-react-instantsearch example (#2544)

* docs: add algolia-react-instantsearch example

* fix: style
This commit is contained in:
Marie-Laure Thuret 2017-07-12 20:00:47 +02:00 committed by Tim Neutkens
parent 24c2e9954a
commit 94c484e80d
11 changed files with 354 additions and 0 deletions

View file

@ -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*

View file

@ -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.

View file

@ -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 }) =>
<div className='hit'>
<div>
<div className='hit-picture'>
<img src={`${hit.image}`} />
</div>
</div>
<div className='hit-content'>
<div>
<Highlight attributeName='name' hit={hit} />
<span>
{' '}- ${hit.price}
</span>
<span>
{' '}- {hit.rating} stars
</span>
</div>
<div className='hit-type'>
<Highlight attributeName='type' hit={hit} />
</div>
<div className='hit-description'>
<Highlight attributeName='description' hit={hit} />
</div>
</div>
</div>
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 (
<InstantSearch
appId='appId' // change this
apiKey='apiKey' // change this
indexName='indexName' // change this
resultsState={this.props.resultsState}
onSearchStateChange={this.props.onSearchStateChange}
searchState={this.props.searchState}
>
<Configure hitsPerPage={10} />
<header>
<h1>React InstantSearch + Next.Js</h1>
<SearchBox />
</header>
<content>
<menu>
<RefinementList attributeName='category' />
</menu>
<results>
<Hits hitComponent={HitComponent} />
</results>
</content>
<footer>
<Pagination />
<div>
See{' '}
<a href='https://github.com/algolia/react-instantsearch/tree/master/packages/react-instantsearch/examples/next-app'>
source code
</a>{' '}
on github
</div>
</footer>
</InstantSearch>
)
}
}

View file

@ -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 =>
<NextHead>
<meta charSet='UTF-8' />
<title>{props.title || ''}</title>
<meta
name='description'
content={props.description || defaultDescription}
/>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' sizes='192x192' href='/static/touch-icon.png' />
<link rel='apple-touch-icon' href='/static/touch-icon.png' />
<link rel='mask-icon' href='/static/favicon-mask.svg' color='#49B882' />
<link rel='icon' href='/static/favicon.ico' />
<meta property='og:url' content={props.url || defaultOGURL} />
<meta property='og:title' content={props.title || ''} />
<meta
property='og:description'
content={props.description || defaultDescription}
/>
<meta name='twitter:site' content={props.url || defaultOGURL} />
<meta name='twitter:card' content='summary_large_image' />
<meta name='twitter:image' content={props.ogImage || defaultOGImage} />
<meta property='og:image' content={props.ogImage || defaultOGImage} />
<meta property='og:image:width' content='1200' />
<meta property='og:image:height' content='630' />
<link
rel='stylesheet'
href='https://unpkg.com/react-instantsearch-theme-algolia@3.0.0/style.min.css'
/>
<link rel='stylesheet' href='../static/instantsearch.css' />
</NextHead>
Head.propTypes = {
title: string,
description: string,
url: string,
ogImage: string
}
export default Head

View file

@ -0,0 +1,3 @@
export * from './head'
export { default as App } from './app'
export { findResultsState } from './instantsearch'

View file

@ -0,0 +1,5 @@
import { createInstantSearch } from 'react-instantsearch/server'
const { InstantSearch, findResultsState } = createInstantSearch()
export { InstantSearch, findResultsState }

View file

@ -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
}
}

View file

@ -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"
}
}

View file

@ -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 (
<div>
<Head title='Home' />
<div>
<App
resultsState={this.props.resultsState}
onSearchStateChange={this.onSearchStateChange}
searchState={
this.state && this.state.searchState
? this.state.searchState
: this.props.searchState
}
/>
</div>
</div>
)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,48 @@
.ais-InstantSearch__root {
align-items: center;
}
header {
display: flex;
flex-direction: column;
align-items: center;
}
content {
display: flex;
}
menu {
flex: 2;
}
footer {
text-align: center;
}
results {
flex: 10;
}
.hit {
display: flex;
align-items: center;
}
.hit-actions {
display: flex;
}
.hit-content {
padding: 0px 10px;
}
.hit-picture img {
width: 80px;
height: 80px;
}
.hit-type {
color: #888888;
font-size: 13px;
}