我用 EJS、Express、Nodejs 和 Yelp API 创建了这个应用程序,这次我想用 React 作为前端,因为我开始学习 React。该应用程序的工作方式是,一旦提交了表单,它就会加载一个新页面,其中包含有关随机餐厅的所有信息。它与 EJS 完美配合,但我无法让它与 React 配合使用。我在表单上使用了 GET 方法,但我不确定如何将它与 React 一起使用。每次提交表单时,我都会收到 401 错误。我并没有真正改变后端的任何东西,所以它基本上是相同的代码。我用 nodemon 检查了它,它确实有效。我还控制台记录了 api 密钥以查看我是否得到它,我确实得到了它。我尝试了不同的东西,但我仍然无法弄清楚我的问题。如果有人可以提供帮助,我将不胜感激!
index.ejs 从以前的应用程序
<section class="whole">
<form id="myForm" action="/selection" method="GET">
<h3>Location</h3>
<input id="city" type="text" name="cityInput" placeholder="Zip or City & State" required>
//the rest of the input form code
<br>
<input class="button" type="submit" value="Submit">
</form>
反应:
App.js
import React from 'react'
import Logo from './images/rest6.png'
import "./style.css";
function App() {
const [formData, setFormData] = React.useState(
{
city: "",
price: "",
category: ""
}
)
function handleChange(event) {
const {name, value, type, checked} = event.target
setFormData(prevChoice => {
return {
...prevChoice,
[name]: value
}
})
}
function handleSubmit(event) {
event.preventDefault()
console.log(formData)
fetch(`/selection`)
.then((response) => console.log(response));
}
return (
<form onSubmit={handleSubmit}>
<h3>Location</h3>
<input type="text" name="city" onChange={handleChange} value={formData.city || ""} placeholder="Zip or City & State" />
<h3 className="priceHeader">Price</h3>
<section id="priceSection">
<label className="radioLabel" htmlFor="priceOne">
<input onChange={handleChange} id="priceOne" type="radio" value="1" name="price" checked={formData.price === "1"} required oninvalid="alert('You must fill out the form!');" />
<div className="radioButtons">
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
</div>
</label>
<label className="radioLabel" htmlFor="priceTwo">
<input onChange={handleChange} id="priceTwo" type="radio" value="2" name="price" checked={formData.price === "2"} />
<div className="radioButtons">
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
</div>
</label>
<label className="radioLabel" htmlFor="priceThree">
<input onChange={handleChange} id="priceThree" type="radio" value="3" name="price" checked={formData.price === "3"} />
<div className="radioButtons">
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
</div>
</label>
<label className="radioLabel" htmlFor="priceFour">
<input onChange={handleChange} id="priceFour" type="radio" value="4" name="price" checked={formData.price === "4"} />
<div className="radioButtons">
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
<i className="fa-sharp fa-solid fa-dollar-sign"></i>
</div>
</label>
<label className="radioLabel" htmlFor="priceAll">
<input onChange={handleChange} id="priceAll" type="radio" value="1,2,3,4" name="price" checked={formData.price === "1,2,3,4"} />
<div className="radioButtons">
<p className="radioInputAll">All</p>
</div>
</label>
</section>
<h3 className="categoryHeader">Categories</h3>
<section className="foodType">
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="mexican" name="category" checked={formData.category === "mexican"} required oninvalid="alert('You must fill out the form!');" />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Mexican</p>
</div>
</label>
<label className="radioLabel" htmlFor="mediterranean">
<input onChange={handleChange} type="radio" id="mediterranean" value="mediterranean" name="category" checked={formData.category === "mediterranean"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Mediterranean</p>
</div>
</label>
<label className="radioLabel" htmlFor="sushi">
<input onChange={handleChange} type="radio" id="sushi" value="sushi" name="category" checked={formData.category === "sushi"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Sushi</p>
</div>
</label>
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="pizza" name="category" checked={formData.category === "pizza"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Pizza</p>
</div>
</label>
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="korean" name="category" checked={formData.category === "korean"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Korean</p>
</div>
</label>
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="coffee" name="category" checked={formData.category === "coffee"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Coffee</p>
</div>
</label>
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="burgers" name="category" checked={formData.category === "burgers"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">Burger</p>
</div>
</label>
<label className="radioLabel">
<input onChange={handleChange} type="radio" value="food" name="category" checked={formData.category === "food"} />
<div className="radioButtons categoryButtons">
<p className="radioInputText">None</p>
</div>
</label>
</section>
<br />
<button>Submit</button>
</form>
)
}
export default App;
index.js
require('dotenv').config()
const express = require('express');
const app = express();
const fetch = require('node-fetch');
const yelp = require('yelp-fusion');
const ejs = require('ejs');
const bodyParser = require('body-parser');
app.set(express.static('public'));
const api_key = process.env.API_KEY
app.set('view engine', 'ejs');
app.use(express.static('public'));
//route for index page
app.get("/", function (req, res) {
res.render("index");
});
const port = process.env.PORT || 3001;
console.log("Running on " + port)
app.listen(port, () => {
console.log(`Listening on port ${port}`)
});
let restaurant,
city,
price,
category,
num = 0;
app.get('/selection', (req, res) => {
console.log('running')
city = req.query.city;
price = req.query.price;
category = req.query.category;
console.log(Object.keys(req.query) )
console.log(Object.keys(req.params) )
console.log(Object.keys(req) )
console.log("category: " + category)
console.log("city: " + city)
console.log("price: " + price)
console.log("RES: " + res.locals.user);
const url = `https://api.yelp.com/v3/businesses/search?location=${city}&categories=${category}&price=${price}&sort_by=best_match&limit=50`
console.log(url)
const options = {
method: 'GET',
headers: {
accept: 'application/json',
Authorization: `Bearer ${api_key}`
}
};
fetch(url, options)
.then(response => response.json())
.then(response => {
console.log("result: ", response);
num = Math.floor(Math.random() * (Object.keys(response.businesses).length));
console.log(response.businesses[num])
console.log("Number of Choices: " + (Object.keys(response.businesses).length))
console.log("random number: " + num)
restaurant = response.businesses[num]
res.render('rest', {
restaurant: restaurant
})
res.status(200).send(response);
})
.catch(err => {
res.status(401).send(err);
console.error(err)
});
});
fetch(`/selection`)
您没有在此处的查询字符串中添加任何内容,因此
req.query
在服务器端将为空。
您可以使用
URLSearchParams轻松编码您的
formData
状态
fetch(`/selection?${new URLSearchParams(formData)}`)
401 是一个奇怪的选择,用于设置服务器端可能发生的任何错误。
相反,我会检测来自 Yelp API 调用的实际响应状态并将其传递回客户端,默认为 500 其他任何内容
fetch(url, options)
.then(async (response) => {
if (!response.ok) {
const err = new Error("Downstream API request failed");
err.status = response.status;
err.cause = await response.text();
throw err;
}
return response.json();
})
.then((response) => {
// ... as above but you don't want res.render()
})
.catch((err) => {
console.error(err, err.status, err.cause);
res.status(err.status ?? 500).send(err.cause ?? err.message);
});