fix(#32): location hook to include the search property

Resolves #32 Now any component that uses the useLocation() hook will have access to the search property.
The search page was also refactored to be a real server component. The form was split off into a client
component that uses server state.
This commit is contained in:
Bret Little 2021-11-05 14:00:38 -04:00
parent e85227a0b9
commit c242319d6d
No known key found for this signature in database
GPG key ID: E31408C812AE535C
3 changed files with 118 additions and 0 deletions

View file

@ -0,0 +1,38 @@
import {useState} from 'react';
import {useServerState} from '@shopify/hydrogen/client';
import {useHistory} from 'react-router-dom';
export default function Search({query}) {
const [newQuery, setNewQuery] = useState(query);
const {pending, setServerState} = useServerState('query', query);
const history = useHistory();
return (
<form
onSubmit={(event) => {
event.preventDefault();
history.push(`/search?query=${newQuery}`);
setServerState('query', newQuery);
}}
className={`mt-4 space-x-2 ${pending ? 'opacity-50' : undefined}`}
>
<label htmlFor="search">Search Products:</label>
<input
autoComplete="off"
name="search"
id="search"
type="search"
value={newQuery}
onChange={(event) => setNewQuery(event.target.value)}
className="px-2 py-1 placeholder-gray-400 text-gray-600 relative bg-white bg-white rounded text-sm border border-gray-400 outline-none focus:outline-none focus:ring"
/>
<button
type="submit"
className="bg-black text-white font-bold p-1"
disabled={pending}
>
Search
</button>
</form>
);
}

View file

@ -0,0 +1,79 @@
import {useLocation} from 'react-router-dom';
import {useShopQuery, Money, Image} from '@shopify/hydrogen';
import gql from 'graphql-tag';
import Layout from '../components/Layout.server';
import ProductCard from '../components/ProductCard.server';
import SearchForm from '../components/SearchForm.client';
export default function Search({query}) {
const {search} = useLocation();
const searchQuery = query || new URLSearchParams(search).get('query');
return (
<Layout>
<h1 className="text-2xl font-bold">Search</h1>
<SearchForm query={searchQuery} />
{searchQuery && <SearchResults query={searchQuery} />}
</Layout>
);
}
function SearchResults({query}) {
const {data} = useShopQuery({query: QUERY, variables: {query}});
return (
<>
<h2 className="text-xl font-medium mt-8">Search results for: {query}</h2>
{data.products.edges.length ? (
<ul className="grid lg:grid-cols-3 gap-6 mt-4">
{data.products.edges.map((edge) => (
<li key={edge.node.id}>
<ProductCard product={edge.node} />
</li>
))}
</ul>
) : (
<p>No results found.</p>
)}
</>
);
}
const QUERY = gql`
fragment SearchProductDetails on Product {
id
title
handle
variants(first: 1) {
edges {
node {
availableForSale
image {
...ImageFragment
}
priceV2 {
...MoneyFragment
}
compareAtPriceV2 {
...MoneyFragment
}
}
}
}
}
query ProductSearch($query: String!) {
products(query: $query, first: 10) {
edges {
node {
...SearchProductDetails
}
}
}
}
${Image.Fragment}
${Money.Fragment}
`;

View file

@ -25,6 +25,7 @@ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
- fix: remove console logs for caching
- fix: lowercased SVG tags in RSC
- fix: make the URL search property available via hooks
- feat: add search page
## 0.5.8 - 2021-11-04