如何在Node.js(Express)中获取查询参数并在React前端实现搜索过滤
问题详情
技术栈
- node.js(express) 服务端
- React 前端
组件文件夹结构
|__src | |__components | |__App | | |__App.js | | |__App.css | |__Business | | |__Business.js | | |__Business.css | |__BusinessList | | |__BusinessList.js | | |__BusinessList.css | |__SearchBar | |__img | |__SearchBar.js | |__SearchBar.css |__util |__yelp.js
预期效果
用户在「Search Businesses」输入框输入搜索词、在「Where?」输入框输入位置,点击「Let's go」按钮后,可以根据输入的分类(例如:Pizza)和位置(例如:Denver)过滤返回的商家列表。
当前实现逻辑
点击「Let's Go」按钮时会调用从yelp.js导入到App.js的searchYelp函数,yelp.js中的searchYelp函数会请求express服务的/api/hello端点,由express服务调用Yelp第三方API获取数据。
当前问题
过滤逻辑不生效,点击「Let's Go」按钮后仅返回随机商家列表,已编写的过滤代码没有正确接入。
相关代码
SearchBar.js
import React from 'react'; import './SearchBar.css'; class SearchBar extends React.Component { constructor(props) { super(props); this.state = { term: '', location: '', sortBy: 'best_match' } this.handleTermChange = this.handleTermChange.bind(this) this.handleLocationChange = this.handleLocationChange.bind(this) this.handleSearch = this.handleSearch.bind(this) this.sortByOptions = { 'Best Match': 'best_match', 'Highest Rated': 'rating', 'Most Reviewed': 'review_count' }; } getSortByClass(sortByOption) { if (this.state.sortBy === sortByOption) { return 'active' } return '' } handleSortByChange(sortByOption) { this.setState({ sortBy: sortByOption }) } handleTermChange(event) { this.setState({ term: event.target.value }) } handleLocationChange(event) { this.setState({ location: event.target.value }) } handleSearch(event) { this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy) event.preventDefault() } renderSortByOptions() { return Object.keys(this.sortByOptions).map(sortByOption => { let sortByOptionValue = this.sortByOptions[sortByOption] return <li onClick={this.handleSortByChange.bind(this, sortByOptionValue)} className={this.getSortByClass(sortByOptionValue)} key={sortByOptionValue}>{sortByOption}</li>; }) } render() { return ( <div className="SearchBar"> {this.searchYelp} <div className="SearchBar-sort-options"> <ul> {this.renderSortByOptions()} </ul> </div> <div className="SearchBar-fields"> <input onChange={this.handleTermChange} placeholder="Search Businesses" /> <input onChange={this.handleLocationChange} placeholder="Where?" /> <button className="SearchBar-submit" onClick={this.handleSearch}>Let's Go</button> </div> </div> ) } }; export default SearchBar;
App.js
import React from 'react'; import BusinessList from '../BusinessList/BusinessList'; import SearchBar from '../SearchBar/SearchBar'; import Yelp from '../../util/yelp'; import './App.css'; class App extends React.Component { constructor(props) { super(props); this.state = { businesses: [], }; this.searchYelp = this.searchYelp.bind(this); } searchYelp(term) { Yelp.searchYelp(term).then((businesses) => { this.setState({ businesses: businesses }) }) } render() { return ( <div className="App"> <SearchBar searchYelp={this.searchYelp} /> <BusinessList businesses={this.state.businesses} /> </div> ) } } export default App;
Yelp.js
const { default: SearchBar } = require("../components/SearchBar/SearchBar"); const Yelp = { searchYelp(term) { return fetch('/api/hello/:term') .then((response) => { console.log(response) return response.json() }).then((jsonResponse) => { console.log(jsonResponse) if (jsonResponse.businesses) { return jsonResponse.businesses.map((business) => { return { id: business.id, imageSrc: business.image_url, name: business.name, address: business.location.address1, city: business.location.city, state: business.location.state, zipCode: business.location.zip_code, category: business.categories.title, rating: business.rating, reviewCount: business.review_count, } }) } }) } } export default Yelp
服务端Server.js
const express = require('express'); const axios = require('axios'); require('dotenv').config(); const cors = require('cors'); const bodyParser = require('body-parser'); const app = express(); app.use(cors()); const port = process.env.PORT || 5000; app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); const apiKey = process.env.APIKEY app.get('/api/hello/:term', (req, res) => { const term = req.params.term const config = { method: 'get', url: 'https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}', headers: { 'Authorization': `Bearer ${apiKey}` } }; axios(config) .then(function (response) { return JSON.stringify(response.data, null, 2) }) .then(function (jsonResponse) { res.send(jsonResponse) }) .catch(function (error) { console.log(error); }); }); app.listen(port, () => console.log(`Listening on port ${port}`));
应用截图

修复方案
1. 修改App.js的searchYelp方法
原方法只接收了term参数,没有接收SearchBar传递的location和sortBy参数,需要补全参数并传递给Yelp的searchYelp方法:
searchYelp(term, location, sortBy) { Yelp.searchYelp(term, location).then((businesses) => { this.setState({ businesses: businesses }) }) }
2. 修改Yelp.js
删除无用的SearchBar导入,补全参数接收逻辑,将term和location作为查询参数传递给后端接口,同时修复categories字段取值错误(Yelp返回的categories是数组,需要取第一个元素的title):
const Yelp = { searchYelp(term, location) { // 对参数编码避免特殊字符报错 return fetch(`/api/hello?term=${encodeURIComponent(term)}&location=${encodeURIComponent(location)}`) .then((response) => { return response.json() }).then((jsonResponse) => { if (jsonResponse.businesses) { return jsonResponse.businesses.map((business) => { return { id: business.id, imageSrc: business.image_url, name: business.name, address: business.location.address1, city: business.location.city, state: business.location.state, zipCode: business.location.zip_code, category: business.categories[0]?.title || '', rating: business.rating, reviewCount: business.review_count, } }) } return [] }) } } export default Yelp
3. 修改Server.js接口
原接口用路径参数只接收了term,且Yelp请求的url用了单引号导致模板字符串不生效,location变量未定义,修改为接收查询参数,修复模板字符串问题:
app.get('/api/hello', (req, res) => { const term = req.query.term const location = req.query.location // 可加非空判断,避免参数缺失报错 if(!term || !location) return res.status(400).send('搜索词和位置不能为空') const config = { method: 'get', // 换成反引号让模板字符串生效 url: `https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}`, headers: { 'Authorization': `Bearer ${apiKey}` } }; axios(config) .then(function (response) { res.json(response.data) }) .catch(function (error) { console.log(error); res.status(500).send('请求数据失败') }); });
内容的提问来源于stack exchange,提问作者Halp_am_stuck
相关产品推荐
相关产品推荐

