我是 React 的新手,对 Next.js 更是陌生
我有一个输入,用户在所有可用城市的列表中按名称搜索城市。
我读过 useSWR 可能会很有趣(在此之前,我在 useEffect 中使用 axios 发出请求)。
一旦我得到了城市数组,我会做一张地图来返回所有匹配的请求(然后我用它来做一个自动完成)。
但是我收到这样的错误:
“错误:重新渲染太多。React 限制了渲染的数量以防止无限循环。”
如果我只是获取数据,它可以工作,但如果我在数组上做地图,我会得到一个无限循环,我不知道为什么。
我的代码:
import React, { useState, useEffect } from "react";
import styles from "./searchBar.module.css";
import { useRouter } from "next/router";
import axios from "axios";
import useSWR from "swr";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSearch, faAngleDown } from "@fortawesome/free-solid-svg-icons";
import installationType from "../public/installation_type_ids.json";
const SearchBar = ({
setSearchSport,
setSearchCity,
searchCity,
searchSport,
setSearchType,
searchType,
setPage,
}) => {
const router = useRouter();
// States for search bar request
const [city, setCity] = useState(searchCity);
const [cityData, setCityData] = useState([]);
const [sport, setSport] = useState(searchSport);
const [title, setTitle] = useState("");
const [type, setType] = useState(searchType);
const [autoComplete, setAutoComplete] = useState([]);
const [displayAutoComplete, setDisplayAutoComplete] = useState(false);
// handle submit button
const handleSubmit = (e) => {
e.preventDefault();
setSearchCity(city);
setSearchSport(sport);
type ? setSearchType(type) : setSearchType("ALL");
setPage(0);
if (router.pathname !== "/points-de-rencontre-sportive")
router.push("/points-de-rencontre-sportive");
};
const url = "https://bouge-api.herokuapp.com/v1.0/city/ids";
const fetcher = (...args) => fetch(...args).then((res) => res.json());
const { data: result, error } = useSWR(url, fetcher);
if (error) return <h1>Oups ! Une erreur est survenue...</h1>;
if (!result) return <h1>Chargement en cours...</h1>;
const handleTest = (e) => {
setCity(e.target.value);
e.target.value === 0
? setDisplayAutoComplete(false)
: setDisplayAutoComplete(true);
if (result && result.data) {
const dataMapped = result.data.map((city) => {
return { city: city.name, type: "city" };
});
let tab = [];
dataMapped.map((item, i) => {
item.name
if (item.name.toLowerCase().includes(city)) {
tab.push(item);
}
return setAutoComplete(tab);
});
}
};
// autocomplete rendering
const renderAutoComplete = autoComplete.map((elem, index) => {
console.log(elem);
if (index <= 9) {
return (
<div
className={styles.autocompleteDiv}
key={index}
onClick={() => {
if (elem.type === "city") {
setCity(elem.city);
}
if (elem.type === "sport") {
setSport(elem.sport);
}
setDisplayAutoComplete(false);
}}
>
<p>{elem.type === "city" ? elem.city : elem.sport}</p>
</div>
);
} else {
return null;
}
});
return (
<div className={styles.searchBar}>
<form className={styles.form} onSubmit={handleSubmit}>
<div>
<label htmlFor="city">Ville</label>
<input
type="text"
id="city"
placeholder="Où veux-tu jouer?"
value={city}
onChange={handleTest}
autoComplete="off" // disable chrome auto complete
/>
</div>
<div>
<label htmlFor="sport">Sport</label>
<input
type="text"
id="sport"
placeholder="Spécifie le sport"
value={sport}
onChange={(e) => {
setSport(e.target.value);
}}
autoComplete="off" // disable chrome auto complete
/>
</div>
<div>
<label htmlFor="title">Nom</label>
<input
type="text"
id="title"
placeholder="Recherche par nom"
value={title}
onChange={(e) => {
setTitle(e.target.value);
let tab = [];
installationType.map((item, i) => {
if (item.installation_type.includes(title)) {
tab.push(item);
}
return setAutoComplete(tab);
});
console.log(tab);
}}
autoComplete="off" // disable chrome auto complete
/>
</div>
<div>
<label htmlFor="type">Type</label>
<select
type="text"
id="type"
placeholder="Type de structure"
value={type}
>
<option value="ALL" defaultValue>
Type de structure
</option>
<option value="AS">Association</option>
<option value="PRIV">Privé</option>
<option value="PUB">Public</option>
<option value="EVENT">Activité</option>
</select>
<i>
<FontAwesomeIcon
icon={faAngleDown}
className={styles.selectIcon}
></FontAwesomeIcon>
</i>
</div>
<button>
<i>
<FontAwesomeIcon
icon={faSearch}
className="fa-lg"
></FontAwesomeIcon>
</i>
Rechercher
</button>
</form>
{displayAutoComplete ? (
<div className={styles.searchResults}>{renderAutoComplete}</div>
) : null}
</div>
);
};
export default SearchBar;