React中的重新渲染次数过多

时间:2020-08-17 11:02:42

标签: javascript reactjs rendering use-state

程序应将输入的用户键入,搜索数据并在下拉列表中返回结果。 当用户输入超过3个符号时,将调用Search(),并且出现“错误:重新渲染过多”。找不到渲染循环。

import LTCityNames from "../lt-city-names.json"; //JSON object

const Openweathermap = () => {
     const [searchList, setSearcList] = useState([]); //drop down list according to search word
     const [text, setText] = useState(""); //text in the input field
  
     const Search = (userinput) => {
         let correctResult = "";
         let dropdownList = [];

     const regex = new RegExp(`^${userinput}`, "i");
        for (let i = 0; i < LTCityNames.length; i++) {
           correctResult = regex.test(LTCityNames[i].name);
        if (correctResult){
           dropdownList.push(LTCityNames[i]);
           setSearcList(dropdownList);
        }   
      }
  };

     const onChangeInput = (userinput) => {
       setText(userinput);
       if (userinput.length > 2) {
         Search(userinput);
       }
     };

   return (
     <input
      value={text}
      onChange={(e) => {onChangeInput(e.target.value)} }
      type="text"
      placeholder="Enter address"
     ></input>
     <div id="myDropdownWeather" className="dropdown-content">
       {searchList.map((itemInArray) => {
         return (
           <ul>
             <li>{itemInArray.name}</li>
           </ul>
         );
       })
}

3 个答案:

答案 0 :(得分:3)

我认为您必须像这样使用useEffect:

  const [text, setText] = useState(""); //text in the input field

  const lastFilter = useRef(text);

  useEffect(() => {
    if (lastFilter.current !== text && text.lenght>2) {
        Search(userinput);
        lastFilter.current = text;
    }
}, [text]);

 const onChangeInput = (event) => {
   var userinput=event.target.value;
   setText(userinput);
 };

并更改

onChange={(e) => {onChangeInput(e.target.value)} }

onChange={(e) => {onChangeInput(e)} } 

答案 1 :(得分:2)

第一:为什么会出现“错误:重新渲染过多”?

使用React Functional Components时,每次调用“ setState” 时,React都会重新加载所有Component,并且由于您在组件内部使用函数,因此每次也会加载这些函数。您的组件更改。因此,当您键入搜索内容时,该元素将无法控制地重新呈现。

解决问题:

  • 每次要在React Functional组件中使用函数时,都必须使用 React.useCallback ,因为这样您就可以精确控制何时将函数重新加载到内存中,从而避免出现错误。
  • 还有一件事情,在您使用React进行返回时,您不能返回多个JSX元素,这也会给您带来很多问题,要解决此问题,您可以使用 fragment元素 <> ... 或将容纳所有其他的任何其他主元素(碎片元素不会干扰您的CSS)

代码:

import React, { useCallback, useState } from 'react';
import LTCityNames from '../lt-city-names.json'; // JSON object

const Openweathermap = () => {
  const [searchList, setSearcList] = useState([]); // drop down list according to search word
  const [text, setText] = useState(''); // text in the input field

  const Search = useCallback((userinput) => {
    const correctResult = '';
    const dropdownList = [];

    const regex = new RegExp(`^${userinput}`, 'i');
    for (let i = 0; i < LTCityNames.length; i++) {
      const correctResult = regex.test(LTCityNames[i].name);
      if (correctResult) {
        dropdownList.push(LTCityNames[i]);
        setSearcList(dropdownList);
      }
    }
  }, []);

  const onChangeInput = useCallback(
    (e) => {
      const userinput = e.target.value;
      setText(userinput);
      if (userinput.length > 2) {
        Search(userinput);
      }
    },
    [Search],
  );

  return (
    <> // Fragment element start
      <input
        value={text}
        onChange={(e) => onChangeInput(e)}
        type="text"
        placeholder="Enter address"
      />
      <div id="myDropdownWeather" className="dropdown-content">
        {searchList.map((itemInArray) => {
          return (
            <ul>
              <li>{itemInArray.name}</li>
            </ul>
          );
        })}
      </div>
    </> // Fragment element end
  );
};

了解useCallback:

  • useCallback是一个React函数,它将接收2个参数,第一个是您的函数,第二个是一个参数数组,更改后将触发该函数在内存中的重新加载(每次您使用来自的元素在函数本身之外,您需要将其用作参数以将函数重新加载到内存中。

const myReactFunction = useCallback(() => {}, [a,b,c....] )

为您改善组件退货:

  • 您无需使用下面列出的任何提示,但它们可以提高代码的可读性。

  • 由于您使用(e) => onChangeInput(e)调用了onChange输入,因此您只能将输入更改为onChangeInput

     <input
         value={text}
         onChange={onChangeInput} // same as (e) => function(e) 
         type="text"
         placeholder="Enter address"
     />
    
  • 第二个技巧是在地图功能内部,因为您使用的是箭头功能,因此无需键入return()

     {searchList.map((itemInArray) => (
         <ul>
             <li>{itemInArray.name}</li>
         </ul>
     ))}
    

答案 2 :(得分:0)

import LTCityNames from "../lt-city-names.json"; //JSON object

const Openweathermap = () => {
     const [searchList, setSearcList] = useState([]); //drop down list according to search word
     const [text, setText] = useState(""); //text in the input field
  
     const Search = (userinput) => {
         let correctResult = "";
         let dropdownList = [];

     const regex = new RegExp(`^${userinput}`, "i");
        for (let i = 0; i < LTCityNames.length; i++) {
           correctResult = regex.test(LTCityNames[i].name);
        if (correctResult){
           dropdownList.push(LTCityNames[i]);
           setSearcList(dropdownList);
        }   
      }
  };

     const onChangeInput = (userinput) => {
       setText(userinput);
       if (userinput.length > 2) {
         Search(userinput);
       }
     };


//remove value={text}
       return (
         <input
          onChange={(e) => {onChangeInput(e.target.value)} }
          type="text"
          placeholder="Enter address"
         ></input>
         <div id="myDropdownWeather" className="dropdown-content">
           {searchList.map((itemInArray) => {
             return (
               <ul>
                 <li>{itemInArray.name}</li>
               </ul>
             );
           })
    }

删除值= {text}