【问题标题】:gatsby build fail when passing navigate state from react component to page将导航状态从反应组件传递到页面时,盖茨比构建失败
【发布时间】: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 = /(&nbsp;|<([^>]+)>)/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


    【解决方案1】:

    locationwindow.location 的缩写,但在构建时,您的代码在没有window 的Node.js 中运行。请考虑在运行location.state.query.trim 调用之前测试window (typeof window !== "undefined") 是否存在,并在window 不存在的情况下回退到默认值。

    【讨论】:

      猜你喜欢
      • 2021-01-14
      • 1970-01-01
      • 2021-04-08
      • 2021-01-21
      • 2019-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多