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

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

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

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

React v19 新功能概覽

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

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

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

React 編譯器

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

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

React 團(tuán)隊(duì)這一創(chuàng)新舉措,不僅簡化了開發(fā)流程,也進(jìn)一步提升了React的性能和穩(wěn)定性,令人期待其在未來版本中的全面應(yīng)用。

服務(wù)端組件

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

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

在即將發(fā)布的React 19中,服務(wù)器端組件將直接融入 React 核心,帶來多重優(yōu)勢:

  • SEO優(yōu)化:服務(wù)端渲染的組件能向網(wǎng)絡(luò)爬蟲提供更豐富的內(nèi)容,進(jìn)而提升搜索引擎排名。
  • 性能飛躍:服務(wù)器=端組件能顯著加快頁面初始加載速度,優(yōu)化整體性能,對內(nèi)容密集型應(yīng)用尤為有效。
  • 服務(wù)器端執(zhí)行:服務(wù)器=端組件使得代碼在服務(wù)器端執(zhí)行成為可能,從而高效處理如API調(diào)用等任務(wù)。

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

使用服務(wù)端組件非常簡單。可以在任何 React 組件中導(dǎo)入服務(wù)端組件,并通過“Actions”來執(zhí)行特定任務(wù)。

'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 允許開發(fā)者將動作與HTML的<form/>標(biāo)簽無縫融合。簡言之,現(xiàn)在可以直接使用Actions替代傳統(tǒng)的onSubmit事件。這些動作被巧妙地設(shè)計(jì)成了HTML表單的屬性,讓表單處理更為靈活和高效。

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

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

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

更值得一提的是,Actions 不僅支持同步操作,還能輕松應(yīng)對異步任務(wù),從而極大地簡化了數(shù)據(jù)提交管理和狀態(tài)更新的流程。React 的目標(biāo)是通過這一創(chuàng)新功能,讓表單處理和數(shù)據(jù)管理變得更加簡單、直觀。

下面來通過一個具體示例來深入了解 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是服務(wù)端組件中的動作。form是一個客戶端組件,它使用submitData作為動作。submitData將在服務(wù)端執(zhí)行。客戶端(form)和服務(wù)端(submitData)組件之間的通信之所以成為可能,正是得益于action屬性。

Web Components

Web Components 賦予我們能力,使用原生HTML、CSS和JavaScript創(chuàng)建自定義組件,并輕松地將它們?nèi)谌隬eb應(yīng)用中,如同操作原生HTML標(biāo)簽般自然流暢。

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

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

這一改進(jìn)將大大提升開發(fā)效率,使我們能夠充分利用現(xiàn)有龐大的 Web Components 生態(tài),為React應(yīng)用增添更多可能性。

盡管目前我們尚未得知具體的實(shí)現(xiàn)細(xì)節(jié),但我期待著它可能帶來的便捷性——或許,我們只需簡單地將 Web Components 導(dǎo)入 React 項(xiàng)目,就像模塊聯(lián)邦那樣。

文檔元數(shù)據(jù)

諸如“標(biāo)題”、“元標(biāo)簽”和“描述”等元素在優(yōu)化搜索引擎優(yōu)化(SEO)和確保可訪問性方面起著至關(guān)重要的作用。在React中,由于單頁面應(yīng)用的普及,跨不同路由管理這些元素可能會有點(diǎn)麻煩。

目前,開發(fā)者通常不得不編寫自定義代碼,或者使用像react-helmet這樣的包來處理路由變更并相應(yīng)更新元數(shù)據(jù)。這個過程可能是重復(fù)的,并且容易出錯,尤其是在處理像元標(biāo)簽這樣的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的組件,它負(fù)責(zé)根據(jù)傳入的屬性更新標(biāo)題和元標(biāo)簽。我們在useEffect中執(zhí)行這些更新。同時,使用JavaScript來更新標(biāo)題和元標(biāo)簽。這個組件將在路由更改時更新。這不是一個干凈的處理方式。

在React 19中,可以直接在React組件中使用標(biāo)題和元標(biāo)簽:

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

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

資源加載

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

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

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

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

增強(qiáng)的 Hooks

use

use 是一個實(shí)驗(yàn)性 React Hook,它可以讓讀取類似于 Promise 或 context 的資源的值。

const value = use(resource);

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

use(Promise)

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

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 模擬數(shù)據(jù)獲取
    setTimeout(() => {
      // 每次刷新時添加一個標(biāo)題
      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>
  );
};

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

官方文檔中,關(guān)于 <Suspense> 有一個警告:

目前尚不支持在不使用固定框架的情況下進(jìn)行啟用 Suspense 的數(shù)據(jù)獲取。實(shí)現(xiàn)支持 Suspense 數(shù)據(jù)源的要求是不穩(wěn)定的,也沒有文檔。React 將在未來的版本中發(fā)布官方 API,用于與 Suspense 集成數(shù)據(jù)源。

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

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

use(Context)

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

import { use } from 'react';

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

這將簡化某些場景下的組件層級結(jié)構(gòu),因?yàn)樵谘h(huán)或條件語句中讀取 context,之前唯一的方法就是將組件一分為二。

在性能方面,這一改進(jìn)也是巨大的進(jìn)步,因?yàn)楝F(xiàn)在即使 context 發(fā)生變化,我們也可以有條件地跳過組件的重新渲染。

useOptimistic

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

import { useOptimistic } from 'react';

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

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

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

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權(quán)威指南"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設(shè)計(jì)"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
    </>
  );
};

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

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

React 將引入一個新組件:<form>,它是創(chuàng)建用于提交信息的交互式控件,可以將一個函數(shù)作為action的屬性值。當(dāng)用戶提交表單時,React 將自動調(diào)用此函數(shù),以執(zhí)行相應(yīng)的操作。

<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>標(biāo)簽上的 prop action無效。要么從元素中刪除它,要么傳遞一個字符串或數(shù)字值以將其保留在 DOM 中。

而在新版本中,可以直接在<form>標(biāo)簽上設(shè)置action屬性。例如,在上面的購物車?yán)又?,?/p>

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 函數(shù)并不是在服務(wù)器端執(zhí)行的,而是在客戶端(例如用戶的瀏覽器)上運(yùn)行的。這個函數(shù)可以是一個異步函數(shù),如網(wǎng)絡(luò)請求,而不阻止其他代碼的執(zhí)行。通過使用addToCart函數(shù),開發(fā)者可以更簡單地處理React中的AJAX表單,例如在搜索表單中。然而,這可能還不足以完全擺脫像 React Hook Form 這樣的第三方庫,因?yàn)樗鼈儾粌H處理表單提交,還包括驗(yàn)證、副作用等多種功能。

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

useFormState

useFormState 是一個可以根據(jù)某個表單動作的結(jié)果更新 state 的 Hook。

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

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

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

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 "添加失?。嘿u完啦";
    }
  };

  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權(quán)威指南"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設(shè)計(jì)"
        addToCart={addToCart}
      />
    </>
  );
};

效果如下:

注意useFormState需要從react-dom中導(dǎo)入,而不是從react中導(dǎo)入。

useFormStatus

useFormStatus 用于獲取上次表單提交的狀態(tài)信息。

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

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

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

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

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權(quán)威指南"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript高級程序設(shè)計(jì)"
        addToCart={addToCart}
      />
    </>
  );
};

添加購物車時效果如下:

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

責(zé)任編輯:姜華 來源: 前端充電寶
相關(guān)推薦

2024-04-28 09:01:06

React 19更新前端

2021-01-28 16:58:12

數(shù)字貨幣加密貨幣區(qū)塊鏈

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前端

2010-04-01 09:03:31

RHEL 5.5

2015-01-04 10:11:32

VMwareWorkstation

2017-04-17 09:01:39

科技新聞早報

2023-05-29 08:38:56

popover控制懸浮層

2020-05-28 13:10:27

PHP開發(fā)編程

2017-03-22 11:59:40

深度神經(jīng)網(wǎng)絡(luò)

2009-01-20 13:03:42

服務(wù)器虛擬化

2022-07-21 10:51:39

物聯(lián)網(wǎng)碎片化物聯(lián)網(wǎng)安全物聯(lián)網(wǎng)

2015-10-26 14:56:23

Ignite Chin微軟技術(shù)大會

2012-10-30 09:24:27

2024-01-02 14:21:33

2025-02-07 09:09:13

2023-11-26 18:13:07

iOS 18蘋果

2009-03-28 09:39:25

Windows 7微軟操作系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 可以在线观看av的网站 | 色网站在线| 一区二区在线免费观看 | 日韩欧美三区 | 91九色视频在线 | 色综合天天天天做夜夜夜夜做 | 国产一区二区自拍 | 久久一二 | 在线观看中文字幕 | 亚洲一级二级三级 | 久久精品亚洲国产奇米99 | 午夜天堂 | 国产xxxx岁13xxxxhd | 91欧美激情一区二区三区成人 | 亚洲色视频 | 成人免费精品 | 国产精品一区二区三区久久久 | 精品久久久久久亚洲精品 | 国产精品亚洲一区 | 国内精品视频免费观看 | 人人艹人人爽 | 国产精品日日摸夜夜添夜夜av | 亭亭五月激情 | 国产成人在线一区二区 | 久久黄色| 久久综合久色欧美综合狠狠 | 欧美一区二区三区在线 | av资源网站 | 欧美精品区 | 蜜臀久久| 精品久久久久久久久亚洲 | 亚洲色图婷婷 | 九九综合 | 91精品国产美女在线观看 | 在线亚洲欧美 | 日韩视频一区在线观看 | 午夜免费在线电影 | 国产一二区视频 | 精品国产一区一区二区三亚瑟 | 欧美三区视频 | 激情久久网 |