成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React 19 要來了!究竟帶來了哪些實用的特性呢?

開發 前端
React 團隊正在緊鑼密鼓地籌備,即將推出備受期待的 v19 版本。那么,React v19 究竟帶來了哪些實用的特性呢?接下來,讓我們一起來探索吧!

自 2022 年 React v18.2 版本發布后,React 社區一直翹首以盼新版本的到來。好消息是,React 團隊正在緊鑼密鼓地籌備,即將推出備受期待的 v19 版本。那么,React v19 究竟帶來了哪些實用的特性呢?接下來,讓我們一起來探索吧!

React v19 新功能概覽

以下是 React 19 即將帶來的新功能的簡要概述:

  • React編譯器:React 團隊正在實現一個新的編譯器。目前,Instagram 已經在使用這項技術,它將在未來的React版本中發布。
  • 服務端組件:經過多年的開發,React引入了服務端組件的概念。現在可以在Next.js中使用這個功能。
  • Actions:Actions 將徹底改變我們與 DOM 元素的交互方式。
  • 文檔元數據:使開發者能夠用更少的代碼完成更多工作。
  • 資源加載:此功能將啟用在后臺加載資源,從而改善應用的加載時間和用戶體驗。
  • Web Components:React 代碼現在將能夠集成 Web Components。
  • 增強的 Hooks:全新 Hook 即將出現,有望徹底改變我們的編碼體驗。

React 19 旨在解決 React 長期以來的一個挑戰:過度重渲染的問題。以前,開發人員依賴于 useMemo()、useCallback()、memo等技術來管理重渲染。新版本將自動處理過度重渲染問題,徹底解放開發者雙手,讓代碼更簡潔、高效。

React 編譯器

目前,React不會自動在狀態改變時重新渲染,這通常需要開發者手動優化,如使用useMemo()、useCallback()和memo API。然而,React團隊認為這是一種“合理的手動折衷”,并非長久之計,他們的目標是讓 React 自行管理這些重渲染過程。

為此,他們創建了“React 編譯器”,它將自動決策如何、何時更新狀態和用戶界面,從而徹底解放開發者的雙手。這也意味著開發者不再需要手動使用上述優化工具。雖然該功能尚未全面發布,但已率先在Instagram等生產環境中得到應用,效果顯著。

React 團隊這一創新舉措,不僅簡化了開發流程,也進一步提升了React的性能和穩定性,令人期待其在未來版本中的全面應用。

服務端組件

如果你尚未聽聞服務器端組件,那你可能錯過了React和Next.js領域的一大革新。過去,React組件主要運行于客戶端,但如今React正引領一場變革——在服務端運行組件。

服務端組件的概念已流傳多年,而 Next.js 則率先將其應用于生產環境。從Next.js 13開始,所有組件默認都是服務器端組件,若想讓組件在客戶端運行,只需使用“use client”指令。

在即將發布的React 19中,服務器端組件將直接融入 React 核心,帶來多重優勢:

  • SEO優化:服務端渲染的組件能向網絡爬蟲提供更豐富的內容,進而提升搜索引擎排名。
  • 性能飛躍:服務器=端組件能顯著加快頁面初始加載速度,優化整體性能,對內容密集型應用尤為有效。
  • 服務器端執行:服務器=端組件使得代碼在服務器端執行成為可能,從而高效處理如API調用等任務。

在React中,所有組件默認是客戶端組件,若需轉為服務器端組件,只需在組件頂部添加“use server”即可。這樣,組件將僅在服務器端運行,不會涉及客戶端。

使用服務端組件非常簡單??梢栽谌魏?React 組件中導入服務端組件,并通過“Actions”來執行特定任務。

'use server';

export default async function requestUsername(formData) {
  const username = formData.get('username');
  if (canRequest(username)) {
    // ...
    return 'successful';
  }
  return 'failed';
}

Actions

在 React 19 中,另一個激動人心的新功能就是Actions。這將是我們在處理表單時工作方式的一個重大改變。

Actions 允許開發者將動作與HTML的<form/>標簽無縫融合。簡言之,現在可以直接使用Actions替代傳統的onSubmit事件。這些動作被巧妙地設計成了HTML表單的屬性,讓表單處理更為靈活和高效。

在Actions之前,我們常依賴于 React 的onSubmit事件來處理表單提交,觸發如搜索等方法的執行。然而,這樣的處理方式通常受限于客戶端,無法在服務端直接執行相關邏輯。

<form onSubmit={search}>  
  <input name="query" />  
  <button type="submit">Search</button>  
</form>

但在 Actions 推出后,結合服務端組件的使用,我們可以輕松地在服務端執行表單提交動作。在JSX中,不再需要繁瑣的onSubmit事件,只需在<form/>標簽中使用action屬性即可。這個屬性的值將指向一個方法,負責處理數據的客戶端或服務端提交。

更值得一提的是,Actions 不僅支持同步操作,還能輕松應對異步任務,從而極大地簡化了數據提交管理和狀態更新的流程。React 的目標是通過這一創新功能,讓表單處理和數據管理變得更加簡單、直觀。

下面來通過一個具體示例來深入了解 Actions 是如何工作的:

"use server"

const submitData = async (userData) => {
  const newUser = {
    username: userData.get('username'),
    email: userData.get('email')
  }
  console.log(newUser)
}
const Form = () => {
    return <form action={submitData}>
        <div>
            <label>Name</label>
            <input type="text" name='username'/>
        </div>
        <div>
            <label>Name</label>
            <input type="text" name="email" />
        </div>
        <button type='submit'>Submit</button>
    </form>
}

export default Form;

在上述代碼中,submitData是服務端組件中的動作。form是一個客戶端組件,它使用submitData作為動作。submitData將在服務端執行??蛻舳耍╢orm)和服務端(submitData)組件之間的通信之所以成為可能,正是得益于action屬性。

Web Components

Web Components 賦予我們能力,使用原生HTML、CSS和JavaScript創建自定義組件,并輕松地將它們融入Web應用中,如同操作原生HTML標簽般自然流暢。

然而,目前將 Web Components 集成到 React 框架中并非易事。我們通常需要將 Web Components 轉化為React組件,或者安裝額外的庫并編寫額外代碼來使它們與 React 兼容,這無疑增加了開發的復雜度。

但好消息是,React 19 將極大地簡化這一過程。未來,當你發現某個實用的 Web Components,如輪播圖組件時,可以輕松地在React項目中引入它,無需繁瑣的轉換工作。

這一改進將大大提升開發效率,使我們能夠充分利用現有龐大的 Web Components 生態,為React應用增添更多可能性。

盡管目前我們尚未得知具體的實現細節,但我期待著它可能帶來的便捷性——或許,我們只需簡單地將 Web Components 導入 React 項目,就像模塊聯邦那樣。

文檔元數據

諸如“標題”、“元標簽”和“描述”等元素在優化搜索引擎優化(SEO)和確??稍L問性方面起著至關重要的作用。在React中,由于單頁面應用的普及,跨不同路由管理這些元素可能會有點麻煩。

目前,開發者通常不得不編寫自定義代碼,或者使用像react-helmet這樣的包來處理路由變更并相應更新元數據。這個過程可能是重復的,并且容易出錯,尤其是在處理像元標簽這樣的SEO敏感元素時。

之前的方式:

import React, { useEffect } from 'react';  
  
const HeadDocument = ({ title }) => {  
  useEffect(() => {  
    document.title = title;  
  
    const metaDescriptionTag = document.querySelector('meta[name="description"]');  
    if (metaDescriptionTag) {  
      metaDescriptionTag.setAttribute('content', '新描述');  
    }  
  }, [title]);  
  
  return null;  
};  
  
export default HeadDocument;

在上面的代碼中,有一個名為HeadDocument的組件,它負責根據傳入的屬性更新標題和元標簽。我們在useEffect中執行這些更新。同時,使用JavaScript來更新標題和元標簽。這個組件將在路由更改時更新。這不是一個干凈的處理方式。

在React 19中,可以直接在React組件中使用標題和元標簽:

const HomePage = () => {  
  return (  
    <>  
      <title>博客</title>  
      <meta name="description" content="博客" />  
      {/* 頁面內容 */}  
    </>  
  );  
}

這在React之前是不可能的。之前唯一的辦法是使用像react-helmet這樣的包。React 19的新特性將大大簡化元數據的管理,使開發者能夠直接在組件內部聲明和更新這些元素,從而提高代碼的可讀性和可維護性。

資源加載

在 React 應用中,有效管理資源加載和性能至關重要,特別是針對圖片和其他資源文件。

通常,瀏覽器會先渲染視圖,然后再加載樣式表、字體和圖片。這可能會導致從非樣式化(或未樣式化內容的閃爍)到樣式化視圖的閃爍。為了緩解這個問題,開發者通常會添加自定義代碼來檢測這些資源何時準備好,確保只在所有內容加載完成后才顯示視圖。

在 React 19 中,隨著用戶瀏覽當前頁面,圖片和其他文件將在后臺加載。這一改進將有助于減少頁面加載時間,降低等待時間。此外,React 19 引入了資源加載的生命周期 Suspense ,包括腳本、樣式表和字體等。這一新特性允許React精確判斷何時內容已準備完畢,可以安全展示給用戶,從而徹底消除了因資源未加載而導致的頁面閃爍問題。同時,React 19 還會提供preload和preinit等新的資源加載API,讓開發者對資源何時加載和初始化擁有更精細的控制權。

通過實現資源的后臺異步加載,React 19 極大地減少了用戶的等待時間,讓他們能夠流暢地與頁面內容進行交互。這一重大改進不僅提升了React應用的性能,也為用戶帶來了更加流暢、愉悅的瀏覽體驗。

增強的 Hooks

use

use 是一個實驗性 React Hook,它可以讓讀取類似于 Promise 或 context 的資源的值。

const value = use(resource);

官方文檔https://zh-hans.react.dev/reference/react/use。

use(Promise)

新的 use hook 可以在客戶端進行“掛起”的 API??梢詫⒁粋€ promise 傳遞給它,React 將會在該 promise 解決之前進行掛起。它的基本語法如下:

import { use } from 'react';

function MessageComponent({ messagePromise }) {
    const message = use(messagePromise);
    // ...
}

下面來看一個簡單的例子:

import * as React from 'react';
import { useState, use, Suspense } from 'react';
import { faker } from '@faker-js/faker';

export const App = () => {
  const [newsPromise, setNewsPromise] = useState(() => fetchNews());

  const handleUpdate = () => {
    fetchNews().then((news) => {
      setNewsPromise(Promise.resolve(news));
    });
  };

  return (
    <>
      <h3>
        新聞列表
    		<button onClick={handleUpdate}>刷新</button>
      </h3>
      <NewsContainer newsPromise={newsPromise} />
    </>
  );
};

let news = [...new Array(4)].map(() => faker.lorem.sentence());

const fetchNews = () =>
  new Promise<string[]>((resolve) =>
    // 使用 setTimeout 模擬數據獲取
    setTimeout(() => {
      // 每次刷新時添加一個標題
      news.unshift(faker.lorem.sentence());
      resolve(news);
    }, 1000)
  );

const NewsContainer = ({ newsPromise }) => (
  <Suspense fallback={<p>請求中...</p>}>
    <News newsPromise={newsPromise} />
  </Suspense>
);

const News = ({ newsPromise }) => {
  const news = use<string[]>(newsPromise);
  return (
    <ul>
      {news.map((title, index) => (
        <li key={index}>{title}</li>
      ))}
    </ul>
  );
};

在上面的例子中,每次刷新時,都會先顯示“請求中...”,請求到數據后進行展示:

官方文檔中,關于 <Suspense> 有一個警告:

目前尚不支持在不使用固定框架的情況下進行啟用 Suspense 的數據獲取。實現支持 Suspense 數據源的要求是不穩定的,也沒有文檔。React 將在未來的版本中發布官方 API,用于與 Suspense 集成數據源。

對于 React 19 來說,use 可能就是用于與 Suspense 集成數據源的官方 API。

這個全新的use hook 與其他的 React Hooks 不同,它可以在循環和條件語句中像 if 一樣被調用。這意味著我們可能不再需要依賴像 TanStack Query 這樣的第三方庫在客戶端進行數據獲取。然而,這仍需進一步觀察,因為 Tanstack Query 的功能遠不止解析 Promise 這么簡單。

use(Context)

這個 use hook 也可以用來讀取 React Context。它與 useContext 作用完全相同,只是可以在循環(如 for)和條件語句(如 if)中調用。

import { use } from 'react';

function HorizontalRule({ show }) {
    if (show) {
        const theme = use(ThemeContext);
        return <hr className={theme} />;
    }
    return false;
}

這將簡化某些場景下的組件層級結構,因為在循環或條件語句中讀取 context,之前唯一的方法就是將組件一分為二。

在性能方面,這一改進也是巨大的進步,因為現在即使 context 發生變化,我們也可以有條件地跳過組件的重新渲染。

useOptimistic

useOptimistic Hook 允許在進行提交動作的同時,能夠樂觀地更新用戶界面,提升用戶體驗。其語法如下:

import { useOptimistic } from 'react';

function AppContainer() {
    const [optimisticState, addOptimistic] = useOptimistic(
        state,
        // 更新函數
        (currentState, optimisticValue) => {
            // 合并并返回帶有樂觀值的新狀態  
        },
    );
}

樂觀更新:一種更新應用程序中數據的策略。這種策略通常會先更改前端頁面,然后向服務器發送請求,如果請求成功,則結束操作;如果請求失敗,則頁面回滾到先前狀態。這種做法可以防止新舊數據之間的跳轉或閃爍,提供更快的用戶體驗。

下面來看一個添加購物車的例子:

import { useState, useOptimistic } from 'react';

const AddToCartForm = ({ id, title, addToCart, optimisticAddToCart }) => {
  const formAction = async (formData) => {
    optimisticAddToCart({ id, title });
    try {
      await addToCart(formData, title);
    } catch (e) {
      // 捕獲錯誤
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">添加到購物車</button>
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      購物車:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const [optimisticCart, optimisticAddToCart] = useOptimistic<Item[], Item>(
    cart,
    (state, item) => [...state, item]
  );

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={optimisticCart} />
      <AddToCartForm
        id="1"
        title="JavaScript權威指南"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設計"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
    </>
  );
};

在上面的例子中,將商品添到購物車時,會先在購物車列表看到剛剛添加的商品,而不必等到數據請求完成。這樣,用戶可以更快地看到更新后的購物車內容,提供更加流暢的用戶體驗。

在介紹 useFormState 之前,先來看以下這個 Hook 使用的背景。

React 將引入一個新組件:<form>,它是創建用于提交信息的交互式控件,可以將一個函數作為action的屬性值。當用戶提交表單時,React 將自動調用此函數,以執行相應的操作。

<form action={handleSubmit} />

注意,如果在 React 18 中添加<form action>屬性,就會收到警告:

?? Warning: Invalid value for prop action on  tag. Either remove it from the element or pass a string or number value to keep it in the DOM.

這里的意思是,<form>標簽上的 prop action無效。要么從元素中刪除它,要么傳遞一個字符串或數字值以將其保留在 DOM 中。

而在新版本中,可以直接在<form>標簽上設置action屬性。例如,在上面的購物車例子中,:

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // 捕獲錯誤
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">添加到購物車</button>
    </form>
  );
};

addToCart 函數并不是在服務器端執行的,而是在客戶端(例如用戶的瀏覽器)上運行的。這個函數可以是一個異步函數,如網絡請求,而不阻止其他代碼的執行。通過使用addToCart函數,開發者可以更簡單地處理React中的AJAX表單,例如在搜索表單中。然而,這可能還不足以完全擺脫像 React Hook Form 這樣的第三方庫,因為它們不僅處理表單提交,還包括驗證、副作用等多種功能。

看完這個新功能,下面就來看看這一部分要介紹的新 Hook:useFormState。

useFormState

useFormState 是一個可以根據某個表單動作的結果更新 state 的 Hook。

const [state, formAction] = useFormState(fn, initialState);

只有在表單提交觸發 action 后才會被更新的值,如果該表單沒有被提交,該值會保持傳入的初始值不變。

例如,這可以用來顯示由表單操作返回的確認消息或錯誤消息。

import { useState } from 'react';
import { useFormState } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const addToCartAction = async (prevState, formData) => {
    try {
      await addToCart(formData, title);
      return '添加成功';
    } catch (e) {
      return "添加失敗:賣完啦";
    }
  };

  const [message, formAction] = useFormState(addToCartAction, null);

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">添加到購物車</button> 
      {message}
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    await new Promise((resolve) => setTimeout(resolve, 1000));
    if (id === '1') {
      setCart((cart: Item[]) => [...cart, { id, title }]);
    } else {
      throw new Error('Unavailable');
    }

    return { id };
  };

  return (
    <>
      <AddToCartForm
        id="1"
        title="JavaScript權威指南"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設計"
        addToCart={addToCart}
      />
    </>
  );
};

效果如下:

注意useFormState需要從react-dom中導入,而不是從react中導入。

useFormStatus

useFormStatus 用于獲取上次表單提交的狀態信息。

const { pending, data, method, action } = useFormStatus();

它不接收任何參數,會返回一個包含以下屬性的 status 對象:

  • pending:布爾值。如果為 true,則表示父級 <form> 正在等待提交;否則為 false。
  • data:包含父級 <form> 正在提交的數據;如果沒有進行提交或沒有父級 <form>,它將為 null。
  • method:字符串,可以是 'get' 或 'post'。表示父級 <form> 使用 GET 或 POST HTTP 方法 進行提交。默認情況下,<form> 將使用 GET 方法,并可以通過 method 屬性指定。
  • action:一個傳遞給父級 <form> 的 action 屬性的函數引用。如果沒有父級 <form>,則該屬性為 null。如果在 action 屬性上提供了 URI 值,或者未指定 action 屬性,status.action 將為 null。

下面來繼續看購物車的例子,將商品添加到購物車成功前,禁用添加按鈕:

import { useState } from 'react';
import { useFormStatus } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // 捕獲錯誤
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <SubmitButton />
    </form>
  );
};

const SubmitButton = () => {
  const { pending } = useFormStatus();
  return (
    <button disabled={pending} type="submit">
      添加到購物車
    </button>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      購物車:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={cart} />
      <AddToCartForm
        id="1"
        title="JavaScript權威指南"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設計"
        addToCart={addToCart}
      />
    </>
  );
};

添加購物車時效果如下:

注意useFormState需要從react-dom中導入,而不是從react中導入。此外,它僅在父級表單使用 action 屬性時才有效。

責任編輯:姜華 來源: 前端充電寶
相關推薦

2024-04-28 09:01:06

React 19更新前端

2021-01-28 16:58:12

數字貨幣加密貨幣區塊鏈

2024-05-08 08:50:39

React19模式UI

2024-12-06 08:00:51

2012-05-03 15:14:38

Firefox 13Beta

2020-03-09 18:34:50

ServerlessDevOps前端

2015-01-04 10:11:32

VMwareWorkstation

2010-04-01 09:03:31

RHEL 5.5

2017-04-17 09:01:39

科技新聞早報

2023-05-29 08:38:56

popover控制懸浮層

2017-03-22 11:59:40

深度神經網絡

2020-05-28 13:10:27

PHP開發編程

2009-01-20 13:03:42

服務器虛擬化

2022-07-21 10:51:39

物聯網碎片化物聯網安全物聯網

2015-10-26 14:56:23

Ignite Chin微軟技術大會

2025-02-07 09:09:13

2024-01-02 14:21:33

2012-10-30 09:24:27

2023-11-26 18:13:07

iOS 18蘋果

2009-03-28 09:39:25

Windows 7微軟操作系統
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本三级网址 | 日韩电影免费在线观看中文字幕 | 男人天堂免费在线 | 女同久久另类99精品国产 | 欧美日韩在线视频一区二区 | 欧美激情国产精品 | 老妇激情毛片免费 | 国产精品伦理一区二区三区 | 欧美视频在线一区 | 亚洲成人一区二区 | 国产精品视频网址 | 欧美日韩亚洲国产综合 | 日本在线一区二区 | 婷婷中文在线 | 亚洲三区在线观看 | 久久久久久国产精品免费免费 | 日韩精品一二三 | 999久久久| 欧美一区二区三区国产 | 精品一区二区三区中文字幕 | 中文字幕 国产 | 日本午夜免费福利视频 | 国产日韩精品一区二区三区 | 亚洲一二三区不卡 | 亚洲激情自拍偷拍 | 视频二区在线观看 | 亚洲成av人片在线观看无码 | 国产成人jvid在线播放 | 男人天堂色 | 国产精品射 | 国产精品一二三区 | www.久草| 美女视频三区 | www久久久 | 日韩成人免费视频 | 免费99视频| 亚洲 中文 欧美 日韩 在线观看 | 欧美三级电影在线播放 | 亚洲区一区二区 | 91精品国产综合久久久久久漫画 | 国产在线一区二区三区 |