【发布时间】:2020-08-12 12:41:53
【问题描述】:
我正在使用 Gatsby 构建一个帮助页面,并有一个搜索栏 (Searchbar.js),我试图在其中传递用户在该字段中的输入 (搜索栏始终存在于页面中(就像Evernote's help page)到执行搜索的组件(search.js),然后将输出传递给实际结果页面 (SearchResults.js)。
当我执行gatsby develop 时,一切正常,但是当我执行gatsby build 时,我收到一个错误,它说它无法读取属性“查询”,因为它未定义(search.js 的第 63 行:@ 987654324@)。为什么构建失败?
Searchbar.js
import React from 'react'
import { navigate } from 'gatsby'
import { FaSearch } from 'react-icons/fa'
import searchbarStyles from "./searchbar.module.css"
export default class Search extends React.Component {
constructor(props) {
super(props)
this.state = {
search: ''
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleSubmit(event) {
event.preventDefault()
var query = this.state.search
navigate(
"/search/",
{
state: { query },
}
)
}
handleChange(event) {
this.setState({
search: event.target.value
})
}
render(){
return (
<div className={searchbarStyles.global_search}>
<div className={searchbarStyles.row}>
<form className={searchbarStyles.search} onSubmit={this.handleSubmit}>
<input
type='text'
id='globalSearchInput'
className=''
placeholder='Search Help & Training'
autoComplete='off'
value={this.state.search}
onChange={this.handleChange}
/>
<button
type='submit'
disabled={!this.state.search}
><FaSearch className={searchbarStyles.searchIcon}/></button>
</form>
</div>
</div>
)
}
}
search.js
import React, { useMemo } from 'react'
import Layout from '../components/Layout'
import SearchResults from '../components/SearchResults'
import { graphql } from 'gatsby'
import Fuse from 'fuse.js'
const matchThreshold = .65
//options for the fuzzy search
var fuseOptions = {
shouldSort: true,
threshold: matchThreshold,
location: 0,
distance: 99999999999,
minMatchCharLength: 1,
includeMatches: true,
includeScore: true,
keys: [
{name: "title", weight: 0.3 },
{name: "content", weight: 0.7}
]
};
function cleanString(string) {
const re = /( |<([^>]+)>)/ig
return string.replace(re,'')
}
function FuzzySearch (query, data) {
fuseOptions.minMatchCharLength = query.length
var dataPrepped = data.map(function(element) {
return {
"title": element.node.frontmatter.title,
"content": cleanString(element.node.html),
"slug": element.node.fields.slug,
}
})
var fuse = useMemo(() => new Fuse(dataPrepped, fuseOptions), [])
var results = fuse.search(query)
//customize the results to only return matches within desired threshold
return results.filter(function(match) {
if(match.score <= matchThreshold) {
return true
}
return false
}).map(function(match) {
return {
"title": match.item.title,
"slug": match.item.slug,
"matches": match.matches
}
})
}
export default ({ location, data }) => {
console.log("SERACH.JS\n")
console.log(JSON.stringify(location))
var search = location.state.query.trim()
var results = []
if(search.length) results = FuzzySearch(search, data.allMarkdownRemark.edges)
return (
<Layout>
<SearchResults FoundItems={results} SearchedTerm={search}> </SearchResults>
</Layout>
)
}
export const query = graphql `
query MyQuery {
allMarkdownRemark {
edges {
node {
fields {
slug
}
frontmatter {
title
date
doctype
}
html
}
}
}
}
`
SearchResults.js
import React from 'react'
import { Link } from 'gatsby'
import searchResultStyles from "./searchresults.module.css"
function resultsPage(resultsBlurb, results) {
return(
<div className={searchResultStyles.content}>
<h1>Search Results</h1>
<p className={searchResultStyles.resultBlurb}>{resultsBlurb}</p>
<ol>
{results.map((match) => (
<li>
<div className={searchResultStyles.resultContent}>
<Link to={match.slug} className={searchResultStyles.resultTitle}>{match.title}</Link>
{match.matches.map(function(instanceOfMatch) {
if(instanceOfMatch.key === "content") {
let startIndex = instanceOfMatch.indices[0][0]
return(
<p className={searchResultStyles.resultExcerpt}>{`...${instanceOfMatch.value.substring(startIndex, startIndex + 100)}...`}</p>
)
}
})}
</div>
</li>
))}
</ol>
</div>
)
}
class SearchResults extends React.Component {
constructor(props) {
super(props)
this.state = {
results: props.FoundItems,
term: props.SearchedTerm,
}
this.updateBlurb = this.updateBlurb.bind(this)
}
updateBlurb() {
let resultsBlurb = `Sorry--could not find any results for "${this.state.term}"`
if (this.state.results.length) {
resultsBlurb = (this.state.results.length === 1) ? `Only 1 item found for "${this.state.term}"` : `Found ${this.state.results.length} items for "${this.state.term}"`
}
return resultsBlurb
}
componentDidUpdate(prevProps) {
if(prevProps!== this.props) {
this.setState ({
results: this.props.FoundItems,
term: this.props.SearchedTerm
})
}
return(resultsPage(this.updateBlurb(), this.props.FoundItems))
}
render() {
return(resultsPage(this.updateBlurb(), this.state.results))
}
}
export default SearchResults
解决方案
(search.js内)
export default ({ location, data }) => {
var search = ''
var results = []
if(typeof window !== "undefiend") search = location.state.query.trim()
if(search.length) results = ...
【问题讨论】:
标签: javascript reactjs react-router react-hooks gatsby