微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

next.js 和 useSWR 出现错误“重新渲染太多”,我不知道为什么?

如何解决next.js 和 useSWR 出现错误“重新渲染太多”,我不知道为什么?

我是 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;

解决方法

获取数据后,调用setCityData方法更新城市数据,这会导致组件重新渲染并再次运行SearchBar组件中的代码,因此它再次调用setCityData然后继续重新-渲染 => 无限重新渲染。

我认为你应该把它放到一个 useEffect 中:

useEffect(() => {
  if (result && result.data) {
    const dataMapped = result.data.map((city) => {
      return { city: city.name,type: "city" };
    });
    setCityData(dataMapped)
  }
},[result])

所以只有当结果有数据时才会更新城市数据

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?