React 中的重新渲染过多

Posted

技术标签:

【中文标题】React 中的重新渲染过多【英文标题】:Too many re-renders in React 【发布时间】:2020-12-06 12:19:34 【问题描述】:

程序应该接受用户输入的输入,搜索数据并在下拉列表中返回结果。 当用户输入超过 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>
         );
       )

【问题讨论】:

【参考方案1】:

我认为你必须像这样使用 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)  

【讨论】:

什么是“过滤器”这是上下文? 哦,很抱歉,我的意思是“文本”,我编辑了我的示例 :)【参考方案2】:

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

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

解决问题:

每次你想在 React 函数式组件中使用一个函数时,你都必须使用 React.useCallback,因为这样你就可以准确地控制一个函数应该在什么时候重新加载到内存中,防止你遇到错误. 还有一件事,当你使用 react 时,你的 return 里面不能返回多个 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(() =&gt; , [a,b,c....] )

提高您的组件回报率:

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

由于您使用(e) =&gt; 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>
 ))

【讨论】:

感谢您的详细解答!不知道 useCalback【参考方案3】:
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

【讨论】:

以上是关于React 中的重新渲染过多的主要内容,如果未能解决你的问题,请参考以下文章

“错误:重新渲染过多。React 限制了渲染次数以防止无限循环。”

收到此错误:错误:重新渲染过多。 React 限制渲染次数以防止无限循环

React Hooks:切换模式下的重新渲染次数过多

使用 React Hooks 重新渲染的次数过多

错误:重新渲染过多。 React 限制了渲染的数量以防止无限循环。即使使用箭头函数

React.js useState hook 导致过多的重新渲染并且无法更新我的状态