【问题标题】:Too many re-renders in ReactReact 中的重新渲染过多
【发布时间】: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>
         );
       })
}

【问题讨论】:

    标签: javascript reactjs rendering use-state


    【解决方案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}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-19
      • 2020-11-27
      • 1970-01-01
      • 2022-01-02
      • 2020-02-23
      • 1970-01-01
      • 2021-03-07
      相关资源
      最近更新 更多