【问题标题】:React component unnecessarily re-renders when I enter input in forms当我在表单中输入输入时,React 组件不必要地重新渲染
【发布时间】:2020-04-13 10:14:49
【问题描述】:

我有一个管理用户登录和注销的反应组件,当用户在登录字段中输入电子邮件和密码时,整个组件(导航栏)在每次击键时都会重新渲染到 Dom,从而降低了速度。

当用户在登录字段中输入凭据时,如何防止导航栏重新呈现?

import React, { useContext,useState } from 'react';
import { Postcontext } from '../contexts/Postcontext';
import axios from 'axios';

const Navbar = () => {


  const { token,setToken } = useContext(Postcontext);
  const [email,setEmail] = useState('');  **state manages user email for login**
  const [password,setPassword] = useState(''); **state manages user password for login**
  const[log,setLog] = useState(true)  **state manages if user logged in or not based on axios post request**


  const login=(e)=>{
    //function for login using axios
      })
  }
  const logout=(e)=>{

    //function for logout using axios
  }
  return (

   <div className="navbar">


     {log?(
        <form>
        <input value={email} type="text" placeholder="email" onChange={(e)=>setEmail(e.target.value)}/>
        <input value={password}  type="text" placeholder="password" onChange={(e)=>setPassword(e.target.value)}/>
        <button onClick={login}>login</button>
        </form>
     ):(
       <button onClick={logout}>logout</button>
     )}
    </div>
  );
}

export default Navbar;

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    这是因为它是同一个组件,需要重新渲染以反映输入文本的变化。如果您希望您的电子邮件更改但不影响导航栏,则创建一个子组件并将输入移动到该组件中,使用子组件中的useState() 管理输入值,当您最终提交并且用户登录时,您可以更新一些全局状态,如 redux 存储或全局身份验证上下文,用于反映和重新呈现导航栏。

    【讨论】:

    • 我做了另外一个只有登录表单的组件,现在子组件更改时导航栏不会重新渲染,但是请注意,当我在输入区域输入时,子组件会重新渲染,我希望有在我完成输入字段的输入之前,无法停止重新渲染
    • 您可以通过使用不受控制的组件和onBlur 上的设置/保存值来做到这一点,但这不是一个好方法。不要担心这些渲染,除非您的页面中有数百万个输入,否则这没什么大不了
    【解决方案2】:

    所以,我遇到了同样的问题,我可以使用useRefuseCallback 解决它,我将尝试以问答形式进行解释。抱歉,如果我不是很清楚,这是我的第一个 StackOverFlow 评论,我是 React 的初学者 :)

    为什么是useRef? 每次看到组件更新时,React 都会通过检查先前对象和当前对象是否相同来重新渲染。在 useRef 的情况下,它仅检查对象 Id 而不是其中的内容,即 Ref 组件内的 current 的值。所以如果你改变当前的值,React 不会考虑这个。 (这就是我们想要的)

    为什么是useCallback? 仅仅是因为它只会在我们调用它或一个(或多个)依赖项发生变化时运行。由于我们使用的是 Ref,所以当它内部的当前值发生变化时,它不会被调用。

    更多信息:https://reactjs.org/docs/hooks-reference.html

    根据以上信息,您的代码应如下所示(仅做登录部分):

    import React, { useContext, useRef } from 'react';
    
    
    const App = () => {
    
    
      const emailRef = useRef(null);  
      const passwordRef = useRef(null);
      const logRef = useRef(null);
    
    
      const loginUpdate = useCallback( async (event) => {
            event.preventDefault();
            // Your logic/code
            // For value do: 
            // const email = emailRef.current.value;
        
         }, [emailRef, passwordRef, logRef]);
    
      
      return (
    
       <div className="navbar">
    
    
         {log?(
            <form>
            <input
              ref={emailRef}
              type="text"
              placeholder="email"
             />
            <input
              ref={passwordRef}
              type="text"
              placeholder="password"
             />
            <button onClick={loginUpdate}>login</button>
            </form>
         ):(
           // Not doing this part because I am lazy :)
           <button onClick={logout}>logout</button>
         )}
        </div>
      );
    }
    
    export default App;
    

    【讨论】:

      【解决方案3】:

      有一些错别字。它对我有用

      https://codesandbox.io/s/cold-sun-s1225?file=/src/App.js:163-208

      import React, { useContext,useState } from 'react';
      // import { Postcontext } from '../contexts/Postcontext';
      // import axios from 'axios';
      
      const App = () => {
      
      
        // const { token,setToken } = useContext();
        const [email,setEmail] = useState('');  
        const [password,setPassword] = useState(''); 
        const[log,setLog] = useState(true)  
      
      
        const login=(e)=>{
          //function for login using axios
            }
      
        const logout=(e)=>{
      
          //function for logout using axios
        }
        return (
      
         <div className="navbar">
      
      
           {log?(
              <form>
              <input value={email} type="text" placeholder="email" onChange={(e)=>setEmail(e.target.value)}/>
              <input value={password}  type="text" placeholder="password" onChange={(e)=>setPassword(e.target.value)}/>
              <button onClick={login}>login</button>
              </form>
           ):(
             <button onClick={logout}>logout</button>
           )}
          </div>
        );
      }
      
      export default App;
      

      【讨论】:

      • 它工作正常,但我担心性能。感谢您的努力
      • 这仍然会在每个输入笔划上重新渲染
      猜你喜欢
      • 2022-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 2018-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多