最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

需要避免的五個react的ref錯誤用法

 更新時間:2024年12月29日 08:38:10   作者:夕水  
react是一個優(yōu)秀的框架,提供了我們很多的便利,但是在使用的過程中,我們也會遇到很多的問題,其中一個就是ref的使用,以下是我列出的5個使用ref的錯誤用法,并提供了正確的用法,需要的朋友可以參考下

前言

react是一個優(yōu)秀的框架,提供了我們很多的便利,但是在使用的過程中,我們也會遇到很多的問題,其中一個就是ref的使用,以下是我列出的5個使用ref的錯誤用法,并提供了正確的用法。

錯誤1: 當使用ref更好時,卻使用state

一個常見的錯誤就是明明使用ref更合適管理狀態(tài)的時候,但是卻使用state來存儲狀態(tài)。例如存儲定時器的間隔時間。

錯誤用法: 我們將定時器間隔時間存儲在狀態(tài)中從而觸發(fā)了不必要的重新渲染。

import { useState, useEffect } from 'react';

export const CustomTimer = () => {
  const [intervalId, setIntervalId] = useState();
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    setIntervalId(id);
    return () => clearInterval(id);
  }, []);

  const stopTimer = () => {
    intervalId && clearInterval(intervalId);
  }

  return (
    <div>
      <p>{time.toLocaleString()}</p>
      <button onClick={stopTimer}>Stop Timer</button>
    </div>
  );
}

正確用法:將定時器間隔存儲在ref中,從而避免了不必要的重新渲染。

ref有個好處就是不會觸發(fā)組件的重新渲染,從而避免了不必要的性能問題。

import { useRef, useEffect } from'react';
 
export const CustomTimer = () => {
  const intervalIdRef = useRef();
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    intervalIdRef.current = id;
    return () => clearInterval(id);
  }, []);
  const stopTimer = () => {
    intervalIdRef.current && clearInterval(intervalIdRef.current);
  }
  return (
    <div>
      <p>{time.toLocaleString()}</p>
      <button onClick={stopTimer}>Stop Timer</button>
    </div>
  );
}

錯誤2: 在設置ref的值之前使用ref.current而不是ref

我們在使用ref傳遞值給某個函數或者子組件的時候,使用的是ref.current而不是ref本身,直接使用ref本身的情況下,ref本身就是一個變化的對象,我們可以在組件渲染時使用ref.current來獲取當前的值,但是在設置ref的值之前,ref.current的值是undefined,這就會導致我們的代碼出現錯誤。

錯誤用法: 下面的代碼無法運行,因為ref.current最初為空, 因此,當代碼運行時,element為空。

import { useRef } from'react';

const useHovered = (element) => {
  const [hovered, setHovered] = useState(false);

  useEffect(() => {
    if(element === null) return;
      element.addEventListener('mouseenter', () => setHovered(true));
      element.addEventListener('mouseleave', () => setHovered(false));
    return () => {
        element.removeEventListener('mouseenter', () => setHovered(true));
        element.removeEventListener('mouseleave', () => setHovered(false));
    };
  }, [element]);

  return hovered;
}
export const CustomHoverDivElement = () => {
  const ref = useRef();
  const isHoverd = useHovered(ref.current);
  return (
    <div ref={ref}>
       Hoverd:{`${isHoverd}`}
    </div>
  );
}

正確用法: 我們需要在設置ref的值之前使用ref.current來獲取當前的值。

import { useRef } from'react';
const useHovered = (ref) => {
  const [hovered, setHovered] = useState(false);
  useEffect(() => {
    if(ref.current === null) return;
      ref.current.addEventListener('mouseenter', () => setHovered(true));
      ref.current.addEventListener('mouseleave', () => setHovered(false));
    return () => {
        ref.current.removeEventListener('mouseenter', () => setHovered(true));
        ref.current.removeEventListener('mouseleave', () => setHovered(false));
    };
  }, [ref]);
  return hovered;
}
export const CustomHoverDivElement = () => {
  const ref = useRef();
  const isHoverd = useHovered(ref);
  return (
    <div ref={ref}>
      Hoverd:{`${isHoverd}`}
    </div>
  );
}

錯誤3: 忘記使用fowardRef

在初學react時,我們可能都犯過這個錯誤,直接給組件傳遞ref參數。事實上,React 不允許你將 ref 傳遞給函數組件,除非它被forwardRef包裝起來。解決辦法是什么?只需將接收 ref 的組件包裝在 forwardRef 中,或為 ref prop 使用另一個名稱即可。

錯誤用法: 下面的代碼無法運行,因為我們沒有使用forwardRef來包裝組件。

import { useRef } from'react';
const CustomInput = ({ ref,...rest }) => {
    const [value, setValue] = useState('');
  useEffect(() => {
    if(ref.current === null) return;
    ref.current.focus();
  }, [ref]);
  return (
    <input ref={ref} {...rest} value={value} onChange={e => setValue(e.target.value)} />
  );
}
export const CustomInputElement = () => {
  const ref = useRef();
  return (
    <CustomInput ref={ref} />
  );
}

正確用法: 我們需要使用forwardRef來包裝組件。

import { useRef, forwardRef } from'react';
const CustomInput = forwardRef((props, ref) => {
  const [value, setValue] = useState('');
  useEffect(() => {
    if(ref.current === null) return;
    ref.current.focus();
  }, [ref]);
  return (
    <input ref={ref} {...props} value={value} onChange={e => setValue(e.target.value)} />
  );
})
export const CustomInputElement = () => {
  const ref = useRef();
  return (
    <CustomInput ref={ref} />
  );
}

錯誤4: 調用函數來初始化ref的值

當你調用函數來設置 ref 的初始值時,該函數將在每次渲染時被調用,如果該函數開銷很大,這將不必要地影響你的應用性能。解決方案是什么?緩存該函數或在渲染期間初始化 ref(在檢查值尚未設置之后)。

錯誤用法: 下面的代碼很浪費性能,因為我們在每次渲染時都調用了函數來設置 ref 的初始值。

import { useState, useRef, useEffect } from "react";

const useOnBeforeUnload = (callback) => {
  useEffect(() => {
    window.addEventListener("beforeunload", callback);
    return () => window.removeEventListener("beforeunload", callback);
  }, [callback]);
}

export const App = () => {
  const ref = useRef(window.localStorage.getItem("cache-date"));
  const [inputValue, setInputValue] = useState("");

  useOnBeforeUnload(() => {
    const date = new Date().toUTCString();
    console.log("Date", date);
    window.localStorage.setItem("cache-date", date);
  });

  return (
    <>
      <div>
        緩存的時間: <strong>{ref.current}</strong>
      </div>
      用戶名:{" "}
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
    </>
  );
}

正確用法: 我們需要緩存該函數或在渲染期間初始化 ref(在檢查值尚未設置之后)。

import { useState, useRef, useEffect } from "react";
const useOnBeforeUnload = (callback) => {
  useEffect(() => {
    window.addEventListener("beforeunload", callback);
    return () => window.removeEventListener("beforeunload", callback);
  }, [callback]);
}
export const App = () => {
  const ref = useRef(null);
  if (ref.current === null) {
    ref.current = window.localStorage.getItem("cache-date");
  }
  const [inputValue, setInputValue] = useState("");
  useOnBeforeUnload(() => {
    const date = new Date().toUTCString();
    console.log("Date", date);
    window.localStorage.setItem("cache-date", date);
  });

  return (
    <>
      <div>
        緩存的時間: <strong>{ref.current}</strong>
      </div>
      用戶名:{" "}
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
    </>
  );
}

錯誤5: 使用每次渲染都會改變的ref回調函數

ref 回調函數可以很好的管理你的代碼,但是,請注意,每當更改時,React 都會調用 ref 回調。這意味著當組件重新渲染時,前一個函數將使用 null 作為參數調用,而下一個函數將使用 DOM 節(jié)點調用。這可能會導致 UI 中出現一些不必要的閃爍。解決方案?確保緩存(使用useCallback) ref 回調函數。

錯誤用法: 下面的代碼無法正常工作,因為每當inputValue或currentTime發(fā)生變化時,ref 回調函數就會再次運行,并且輸入將再次成為焦點。

import { useEffect, useState } from "react";

const useCurrentTime = () => {
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const intervalId = setInterval(() => {
      setTime(new Date());
    }, 1_000);
    return () => clearInterval(intervalId);
  });
  return time.toString();
}

export const App = () => {
  const ref = (node) => {
    node?.focus();
  };
  const [nameValue, setNameValue] = useState("");
  const currentTime = useCurrentTime();

  return (
    <>
      <h2>當前時間: {currentTime}</h2>
      <label htmlFor="name">用戶名: </label>
      <input
        id="name"
        ref={ref}
        value={nameValue}
        onChange={(e) => setNameValue(e.target.value)}
      />
    </>
  );
}

正確用法: 我們需要確保緩存(使用useCallback) ref 回調函數。

import { useEffect, useState, useCallback } from "react";
const useCurrentTime = () => {
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const intervalId = setInterval(() => {
      setTime(new Date());
    }, 1_000);
    return () => clearInterval(intervalId);
  });
  return time.toString();
}
export const App = () => {
  const ref = useCallback((node) => {
    node?.focus();
  }, []);
  const [nameValue, setNameValue] = useState("");
  const currentTime = useCurrentTime();
  return (
    <>
      <h2>當前時間: {currentTime}</h2>
      <label htmlFor="name">用戶名: </label>
      <input
        id="name"
        ref={ref}
        value={nameValue}
        onChange={(e) => setNameValue(e.target.value)}
      />
    </>
  );
}

以上就是需要避免的五個react的ref錯誤用法的詳細內容,更多關于react的ref錯誤用法的資料請關注腳本之家其它相關文章!

相關文章

  • React配置Redux并結合本地存儲設置token方式

    React配置Redux并結合本地存儲設置token方式

    這篇文章主要介紹了React配置Redux并結合本地存儲設置token方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React項目中className運用及問題解決

    React項目中className運用及問題解決

    這篇文章主要為大家介紹了React項目中className運用及問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • React組件的生命周期深入理解分析

    React組件的生命周期深入理解分析

    組件的生命周期就是React的工作過程,就好比人有生老病死,自然界有日月更替,每個組件在網頁中也會有被創(chuàng)建、更新和刪除,如同有生命的機體一樣
    2022-12-12
  • React中mobx和redux的區(qū)別及說明

    React中mobx和redux的區(qū)別及說明

    這篇文章主要介紹了React中mobx和redux的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • 一文帶你了解React中的并發(fā)機制

    一文帶你了解React中的并發(fā)機制

    React 18.2.0 引入了一系列并發(fā)機制的新特性,旨在幫助各位開發(fā)者更好地控制和優(yōu)化應用程序的性能和用戶體驗,下面我們就來看看如何利用這些新特性構建更高效、更響應式的應用程序吧
    2024-03-03
  • React如何實現像Vue一樣將css和js寫在同一文件

    React如何實現像Vue一樣將css和js寫在同一文件

    這篇文章主要介紹了React如何實現像Vue一樣將css和js寫在同一文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • React實現簡單登錄的項目實踐

    React實現簡單登錄的項目實踐

    登錄、注冊、找回密碼是前端項目經常遇到的需求,本文主要介紹了React實現簡單登錄的項目實踐,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • React-vscode使用jsx語法的問題及解決方法

    React-vscode使用jsx語法的問題及解決方法

    很多朋友在安裝插件ES7 React/Redux/GraphQL/React-Native snippets還是不能完全支持jsx語法,糾結是什么原因呢,該如何處理呢,下面小編給大家分享本文幫助大家解決React-vscode使用jsx語法問題,感興趣的朋友一起看看吧
    2021-06-06
  • React Hook useState useEffect componentDidMount componentDidUpdate componentWillUnmount問題

    React Hook useState useEffect componentD

    這篇文章主要介紹了React Hook useState useEffect componentDidMount componentDidUpdate componentWillUnmount問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 詳解React Native與IOS端之間的交互

    詳解React Native與IOS端之間的交互

    React Native (簡稱RN)是Facebook于2015年4月開源的跨平臺移動應用開發(fā)框架,是Facebook早先開源的JS框架 React 在原生移動應用平臺的衍生產物,支持iOS和安卓兩大平臺。本文將介紹React Native與IOS端之間的交互。
    2021-06-06

最新評論

阿城市| 新河县| 辽阳市| 延川县| 广西| 邵阳县| 册亨县| 星座| 仲巴县| 汉中市| 鲁山县| 垦利县| 玉环县| 桐乡市| 呼伦贝尔市| 昌图县| 磐石市| 金秀| 达孜县| 河南省| 安福县| 安丘市| 瑞安市| 吴忠市| 博兴县| 绥中县| 荣成市| 大厂| 文登市| 达日县| 黄山市| 天祝| 龙口市| 阳谷县| 勐海县| 武乡县| 京山县| 云龙县| 巧家县| 班戈县| 台南市|