精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

React19 她來了,她來了,他帶著禮物走來了

開發 前端
xdm,5.1玩的還可以嗎?既然已經玩夠了,那么我們又得切換到上班模式。其實這篇文章是5.1之前開始寫的,為了讓大家能夠有一個輕松的假期,索性就沒在節內發送。今天我們來聊聊前端的內容。

前言

xdm,5.1玩的還可以嗎?既然已經玩夠了,那么我們又得切換到上班模式。其實這篇文章是5.1之前開始寫的,為了讓大家能夠有一個輕松的假期,索性就沒在節內發送。今天我們來聊聊前端的內容。

React19她來了,她來了,她帶著??走來了。時隔2年多,React終于有了新版本了。你可知道,我們這兩年是如何過來的嗎?!

就在2024/04/25,我們可以通過npm install react@beta在本地安裝React19了。

圖片圖片

在React19沒發布之前,從各種小道消息中知曉了React在新版本中新增了很多特性,并且優化了編譯流程。因為,本著沒有調查就沒有發言權的態度,我就遲遲沒有下筆。

既然,React19我們可以唾手可得了,那高低需要研究一波。

下面,我們就來看看她到底給我帶來了啥!

好了,天不早了,干點正事哇。

我們能所學到的知識點

  1. React v19 的新特性概覽
  2. React 編譯器
  3. 服務器組件(RSC)
  4. 動作(Action)
  5. Web Components
  6. 文檔元數據
  7. 資源加載
  8. 新的 React Hooks

1. React v19 的新特性概覽

  • React 編譯器:React 實現了一個新的編譯器。目前,Instagram 已經在利用這項技術了。
  • 服務器組件(RSC):經過多年的開發,React 引入了服務器組件,而不是需要借助Next.js
  • 動作(Action):動作也將徹底改變我們與 DOM 元素的交互方式。
  • 文檔元數據:這是另一個備受期待的改進,讓我們能夠用更少的代碼實現更多功能。
  • 資源加載:這將使資源在后臺加載,從而提高應用程序的加載速度和用戶體驗。
  • Web Components:React 代碼現在可以讓我們集成 Web Components。
  • 增強的 hooks:引入了很多令人興奮的新 hooks,將徹底改變我們的編碼體驗。

下面我們就來一一探索其中的奧秘。

2. React 編譯器

其實React 編譯器就是之前早在React 2021年開發者大會上提出的React Forget,只不過最近才將其改為React 編譯器。

React 編譯器是一個「自動記憶編譯器」,可以自動執行應用程序中的所有記憶操作。

React 編譯器 的核心幾乎與 Babel 完全解耦,編譯器內核其實就是「舊的 AST 輸入,新的 AST 輸出」。在后臺,編譯器使用自定義代碼表示和轉換管道來執行語義分析。

React19之前的版本,當狀態發生變化時,React有時會重新渲染不相干的部分。從React的早期開始,我們針對此類情況的解決方案一直是「手動記憶化」。在之前的API中,這意味著應用useMemo、useCallback和memo API來手動調整React在狀態變化時重新渲染的部分。但手動記憶化只是一種「權宜之計」,它會使代碼變得復雜,容易出錯,并需要額外的工作來保持更新。React 團隊意識到手動優化很繁瑣,并且使用者對這種方式「怨聲載道」。

因此,React 團隊創建了React 編譯器。React 編譯器現在將管理這些重新渲染。React 將「自行決定何時以及如何改變狀態并更新 UI」。

有了這個功能,我們不再需要手動處理這個問題。這也意味著讓人詬病的 useMemo()、useCallback() 和 memo要被歷史的車輪無情的碾壓。

React19 !=React 編譯器

圖片圖片

由于React 編譯器還未開源,所以我們無法得知其內部實現細節,不過我們可以從以往的動態中窺探一下。下面是一些與其相關的資料和視頻。

  • React 編譯器_youtube地址[1]
  • React Forget的基本介紹[2]

3. 服務器組件(RSC)

其實,在2023年,我們就注意到RSC,并且寫了幾篇文章。

圖片圖片

對應的文章鏈接如下

  1. React Server Components手把手教學
  2. 用Rust搭建React Server Components 的Web服務器

服務器組件的想法已經流傳了多年,Next.js 是第一個在生產環境中實現它們的。從 Next.js 13 開始,「默認情況下所有組件都是服務器組件」。要使組件在客戶端運行,我們需要使用'use client'指令。

在 React 19 中,服務器組件將直接集成到 React 中,帶來了一系列優勢:

  1. 數據獲取: 服務器組件允許我們將數據獲取移至服務器端,更接近數據源。這可以通過減少獲取渲染所需數據的時間和客戶端需要發出的請求數量來提高性能。
  2. 安全性: 服務器組件允許我們將「敏感數據和邏輯」保留在服務器端,而無需暴露給客戶端的風險。
  3. 緩存: 由于在服務器端渲染,結果可以被緩存并在后續請求和跨用戶時重復使用。這可以通過減少每個請求所需的渲染和數據獲取量來提高性能并降低成本。
  4. 性能: 服務器組件為我們提供了額外的工具來從基線優化性能。例如,如果我們從一個完全由客戶端組件組成的應用程序開始,將非交互式UI部分移至服務器組件可以減少所需的客戶端JavaScript。這對于網絡較慢或設備性能較低的用戶來說是有益的,因為瀏覽器需要下載、解析和執行的客戶端JavaScript更少。
  5. 初始頁面加載和首次內容渲染(FCP): 在服務器端,我們可以生成HTML,允許用戶立即查看頁面,而無需等待客戶端下載、解析和執行渲染頁面所需的JavaScript。
  6. SEO:RSC通過為網絡爬蟲提供更可訪問的內容來增強搜索引擎優化。
  7. 流式傳輸: 服務器組件允許我們將渲染工作分割成塊,并在它們準備就緒時將其流式傳輸到客戶端。這允許用戶在不必等待整個頁面在服務器端渲染完成的情況下,更早地看到頁面的某些部分。

如何使用服務器組件

默認情況下,React 中的所有組件都是客戶端組件。只有使用 'use server' 時,組件才是服務器組件。

我們只需要將 'use server' 添加為組件的第一行即可。這將使組件成為服務器組件。它不會在客戶端運行,只會在服務器端運行。

'use server';

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

4. 動作(Action)

在 React19中,另一個令人興奮的新增功能將是Action。這將是我們處理表單的重大變革。

何為Action

使用異步轉換的函數被稱為Action(動作)。Action自動管理數據的提交:

  1. Pending狀態:Action提供了一個state

請求開始時,代表對應的狀態- pending狀態

請求結束時,狀態自動重置

  1. Optimistic更新:Action支持新的useOptimistic hook,因此我們可以在請求提交時向用戶顯示即時反饋。
  2. 錯誤處理:Action提供錯誤處理,因此我們可以在請求失敗時顯示Error Boundary,并自動恢復Optimistic更新為其原始值。
  3. 增強表單操作:<form>元素支持將函數傳遞給action和formAction props。
  • 傳遞給action props的函數默認使用Action機制,并在提交后自動重置表單

Action將允許我們將action與<form/>標簽 集成。簡單來說,我們將能夠用action替換 onSubmit 事件。

在使用Action之前

在下面的代碼片段中,我們將利用 onSubmit事件,在表單提交時觸發搜索操作。

<form notallow={search}>
  <input name="query" />
  <button type="submit">查詢</button>
</form>

使用Action后

隨著服務器組件的引入,  Action可以在服務器端執行。在我們的 JSX 中,我們可以刪除 <form/> 的 onSubmit 事件,并使用 action 屬性。action 屬性的值將是一個「提交數據的方法」,可以在客戶端或服務器端提交數據。

我們可以使用Action執行同步和異步操作,簡化數據提交管理和狀態更新。目標是使處理表單和數據更加容易。

"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>用戶名</label>
            <input type="text" name='username'/>
        </div>
        <div>
            <label>郵箱</label>
            <input type="text" name="email" />
        </div>
        <button type='submit'>提交</button>
    </form>
}

export default Form;

在上面的代碼中,submitData 是服務器組件中的Action。form 是一個客戶端組件,它使用 submitData 作為Action。submitData 將在服務器上執行。

5. Web Components

如果大家公司技術方案不是單一的。例如,公司有很多項目,并且項目中使用了不同的技術框架React/Vue等。然而,此時有一個功能需要多項目多框架使用,那么我們可以考慮一下,將此功能用Web Components實現。

Web Components

Web 組件允許我們使用原生 HTML、CSS 和 JavaScript 創建自定義組件,無縫地將它們整合到我們的 Web 應用程序中,就像使用HTML 標簽一樣。

三要素

  1. Custom elements(自定義元素):一組 JavaScript API,允許我們定義 custom elements 及其行為,然后可以在我們的用戶界面中按照需要使用它們。

通過 class A extends HTMLElement {} 定義組件,

通過 window.customElements.define('a-b', A) 掛載已定義組件。

  1. Shadow DOM(影子 DOM ):一組 JavaScript API,用于將封裝的“影子” DOM 樹附加到元素(「與主文檔 DOM 分開呈現」)并控制其關聯的功能。
  • 通過這種方式,我們可以「保持元素的功能私有」,這樣它們就可以被腳本化和樣式化,而不用擔心與文檔的其他部分發生沖突。

  • 使用 const shadow = this.attachShadow({mode : 'open'}) 在 WebComponents 中開啟。

  1. HTML templates(HTML 模板)slot :template 可以簡化生成 dom 元素的操作,不再需要 createElement 每一個節點。

雖然 WebComponents 有三個要素,但卻不是缺一不可的,WebComponents

  • 借助 shadow dom  來實現「樣式隔離」,
  • 借助 templates 來「簡化標簽」的操作。

內部生命周期函數(4個)

  1. connectedCallback: 當 WebComponents 「第一次」被掛在到 dom 上是觸發的鉤子,并且只會觸發一次。

類似  React 中的 useEffect(() => {}, []),componentDidMount。

  1. disconnectedCallback: 當自定義元素與文檔 DOM 「斷開連接」時被調用。
  2. adoptedCallback: 當自定義元素被「移動」到新文檔時被調用。
  3. attributeChangedCallback: 當自定義元素的被監聽屬性變化時被調用。

如果不想用原生寫,那么我們可以選擇一些成熟的框架,例如Lit[3]

圖片圖片

React19 兼容 Web Components

在React19之前,在 React 中集成 Web Components并不直接。通常,我們需要將 Web Components轉換為 React 組件,或者安裝額外的包并編寫額外的代碼來使 Web Components與 React 協同工作。

React 19 將幫助我們更輕松地將 Web Components整合到我們的 React 代碼中。如果我們遇到一個非常有用的 Web Components,我們可以無縫地將其整合到 React 項目中,而不需要將其轉換為 React 代碼。

這簡化了開發流程,并允許我們在 React 應用程序中利用現有 Web Components的廣泛生態系統。

6. 文檔元數據

TKD

在做SEO時,我們需要在<meta>中處理title/keywords/description的信息。

  1. title的權重最高,利用title提高頁面權重
  2. keywords相對權重較低,作為頁面的輔助關鍵詞搜索
  3. description的描述一般會直接顯示在搜索結果的介紹中

當然處理SEO不僅僅這點方式,還有在項目中新增Sitemap.xml還有使用rel=canonical的連接,想了解更多的方式,可以參考SEO教程[4]

處理SEO

經常借助編寫自定義代碼或使用像 react-helmet[5] 這樣的包來處理路由更改并相應地更新元數據。這個過程可能會重復,而且容易出錯,特別是在處理像 meta 標簽這樣對 SEO 敏感的元素時。

React19之前的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 的組件,基于props 更新title和 meta 標簽。我們在 useEffect 鉤子中更新這些內容。我們還使用 JavaScript 來更新標題和 meta 標簽。這個組件將在路由更改時更新。

React19的SEO

使用 React19后,我們可以直接在 React 組件中使用<title>和 <meta> 標簽:

Const HomePage = () => {
  return (
    <>
      <title>React19</title>
      <meta name="description" content="前端柒八九" />
      // 頁面內容
    </>
  );
}

當然,我們可以基于props來更新title/meta中的對應信息。

7.資源加載

在 React 中,我們需要特別關心應用程序的加載體驗和性能,特別是圖片和其他資源文件。

通常,視圖會首先在瀏覽器中渲染,然后是樣式表、字體和圖片。這可能會導致FOIT或者FOUT。

我們在瀏覽器之性能指標-CLS中有過介紹,這里我們就拿來主義了。

FOIT/FOUT

FOIT和FOUT是與Web字體加載相關的術語。

FOIT代表"Flash of Invisible Text",意為「不可見文本的閃爍」。

當使用Web字體時,瀏覽器在下載字體文件時,會顯示一段時間的空白文本,直到字體文件完全加載完成。這段時間內,用戶可能會看到頁面上出現了空白文本,然后突然閃現出字體樣式。這種體驗被稱為FOIT。

FOUT代表"Flash of Unstyled Text",意為「未樣式化文本的閃爍」。

與FOIT類似,當使用Web字體時,瀏覽器可能會「先顯示系統默認字體」,然后在字體文件加載完成后,突然將文本樣式化為所需的Web字體。這種體驗被稱為FOUT。

FOIT和FOUT都是由于Web字體加載的延遲而導致的不佳用戶體驗。用戶可能會看到文本內容在加載過程中發生閃爍或樣式變化,給頁面的整體穩定性和一致性帶來了困擾。為了解決FOIT和FOUT問題,可以使用CSS屬性,如font-display,來控制字體加載和顯示的方式,以平滑地呈現文本內容,提高用戶體驗。

或者我們可以「添加自定義代碼來檢測這些資源何時準備好」,確保視圖只在所有內容加載完畢后顯示。

在 React 19 中,當用戶瀏覽當前頁面時,圖片和其他文件將「在后臺加載」。

這個改進應該有助于提高頁面加載速度并減少等待時間。

此外,React 還引入了用于資源加載的生命周期 Suspense,包括script、樣式表和字體。這個特性使 React 能夠確定內容何時準備好顯示,消除了任何FOUT的閃爍現象。

還有新的資源加載 API,比如 preload 和 preinit,可以提供更大的控制力,確定何時加載和初始化資源。

通過允許資源在后臺異步加載,React 19減少了等待時間,確保用戶可以在不間斷的情況下與內容進行交互。

8. 新的 React Hooks

自從React16.8引入Hook機制以來,React的開發模式就發生了翻天覆地的變化。她提供的各種內置Hook大大提高了我們開發組件的效率。并且,我們還可以通過封裝各種自定義Hook來處理共有邏輯。也就是說,Hook在React中有舉足輕重的地位。Hook已經成為了開發React的主流編程模式。

雖然,Hook為我們帶來了很多的便利,但是有些Hook的使用卻需要各種限制,稍不留神就會讓頁面陷入萬劫不復的地步。所以React19對一些我們平時用起來不咋得心應手的Hook做了一次升級。

在 React 19 中,我們使用 useMemo、forwardRef、useEffect 和 useContext 的方式將會改變。這主要是因為將引入一個新的 hook,即 use。

useMemo()

在 React19 之后,我們不再需要使用 useMemo() hook,因為 React編譯器 將會自動進行記憶化。

之前的寫法

import React, { useState, useMemo } from 'react';

function ExampleComponent() {
  const [inputValue, setInputValue] = useState('');

  // 記住輸入框是否為空的檢查結果
  const isInputEmpty = useMemo(() => {
    console.log('檢測輸入框是否為空');
    return inputValue.trim() === '';
  }, [inputValue]);

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <p>{isInputEmpty ? 'Input 為空' : 'Input有值'}</p>
    </div>
  );
}

export default ExampleComponent;

之后的寫法

在下面的例子中,我們可以看到在 React19 之后,我們不再需要自己來做記憶化,React19 將會在后臺自動完成。

import React, { useState } from 'react';

function ExampleComponent() {
  const [inputValue, setInputValue] = useState('');

  const isInputEmpty = () => {
    console.log('檢測輸入框是否為空');
    return inputValue.trim() === '';
  });

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <p>{isInputEmpty ? 'Input 為空' : 'Input有值'}</p>
    </div>
  );
}

export default ExampleComponent;

forwardRef()

ref 現在將作為props傳遞而不是使用 forwardRef() hook。

這將簡化代碼。因此,在 React19 之后,我們不需要使用 forwardRef()。

之前的寫法

import React, { forwardRef } from 'react';

const ExampleButton = forwardRef((props, ref) => (
  <button ref={ref}>
    {props.children}
  </button>
));

之后的寫法

ref 可以作為屬性傳遞。不再需要 forwardRef()。

import React from 'react';

const ExampleButton = ({ ref, children }) => (
  <button ref={ref}>
    {children}
  </button>
);

新的 use() hook

React19 將引入一個新的 hook,名為 use()。這個 hook 將簡化我們如何使用 promises、async 代碼和 context。

語法

const value = use(resource);

示例1:接收async函數

下面的代碼是使用 use hook 進行 fetch 請求的示例:

import { use } from "react";

const fetchUsers = async () => {
    const res = await fetch("遠程地址");
    return res.json();
  };
  
const UsersItems = () => {
  const users = use(fetchUsers());

  return (
    <ul>
      {users.map((user) => (
        <div key={user.id} >
          <h2>{user.name}</h2>
          <p>{user.email}</p>
        </div>
      ))}
    </ul>
  );
}; 
export default UsersItems;

讓我們理解一下代碼:

  • fetchUsers進行遠程數據請求
  • 我們使用 use hook 執行 fetchUsers,而不是使用 useEffect 或 useState hooks。
  • use hook 的返回值是 users,其中包含 GET 請求的響應(users)。
  • 在return中,我們使用 users進行對應信息的渲染處理。

示例2:接收context對象

我們以后可以直接將context對象傳人到use()中,從而達到將context引入組件的目的。而不需要useContext()了。

使用createContext定義全局變量

這里我們定義

import { createContext, useState, use } from 'react';

const ThemeContext = createContext();

const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
在組件中使用use()獲取context信息
const Card = () => {
  // use Hook()
  const { theme, toggleTheme } = use(ThemeContext);

  return (
    // 基于theme/toggleTheme 渲染頁面或者執行對應的操作
  );
};

const Theme = () => {
  return (
    <ThemeProvider>
      <Card />
    </ThemeProvider>
  );
};

export default Theme

上面代碼中有幾點需要簡單解釋一下:

  • ThemeProvider 負責提供 context。
  • Card 是我們將消費 context 的組件。為此,我們將使用新的 hook use 來消費 context。

衍生一下

其實吧,use的內部實現很簡單,就是基于傳人的對象類型進行返回數據即可。

圖片圖片

針對,其內部是如何實現的,我們后期會有專門的文章來介紹,這里就不在過多解釋了。

useFormStatus() hook

在 React19 中,我們還有新的 hooks 來處理表單狀態和數據。這將使處理表單更加流暢和簡單。將這些 hooks 與 Action結合使用將使處理表單和數據更加容易。

React19 中的這個新 hook 將幫助我們更好地控制你創建的表單。它將提供關于上次表單提交的狀態信息。

基礎語法

這是它的語法:

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

或者簡化的版本:

const { status } = useFormStatus()
  • pending:如果表單處于待處理狀態,則為 true,否則為 false。
  • data:一個實現了 FormData 接口的對象,其中包含父 <form> 提交的數據。
  • method:HTTP 方法 – GET,或 POST。

默認情況下將是 GET。

  • action:一個函數引用。

案例展示

useFormStatus是從react-dom庫中導出的

import { useFormStatus } from "react-dom";

function Submit() {
  const status = useFormStatus();
  return <button disabled={status.pending}>
        {status.pending ? '正在提交...' : '提交完成'}
    </button>;
}

// ==== 父組件 ==引入Submit ====

const formAction = async () => {
  // 模擬延遲 3 秒
  await new Promise((resolve) => setTimeout(resolve, 3000));
}

const FormStatus = () => {
  return (
    <form action={formAction}>
      <Submit />
    </form>
  );
};

export default FormStatus;

讓我們簡單解釋一下上面代碼:

  • Submit通過useFormStatus可以獲取此時from表單的提交狀態,并基于一些狀態渲染一些輔助信息
  • formAction是執行異步提交的處理

在上面的代碼中,當表單提交時,從 useFormStatus hook 我們將獲得一個 pending 狀態。

  • 當 pending 為 true 時,UI 上會顯示 "正在提交..." 文本。
  • 一旦 pending 為 false,"正在提交..." 文本將被更改為 "提交完成"。

當我們想要知道表單提交的狀態并相應地顯示數據時,它會很有用。

useFormState() hook

React19 中的另一個新 hook 是 useFormState。它允許我們根據表單提交的結果來更新狀態。

語法

這是它的語法:

const [state, formAction] = 
      useFormState(
        fn, 
        initialState, 
        permalink?
      );
  • fn:表單提交或按鈕按下時要調用的函數。
  • initialState:我們希望狀態初始值是什么。它可以是任何可序列化的值。在首次調用操作后,此參數將被忽略。
  • permalink:這是可選的。一個 URL 或頁面鏈接,如果 fn 將在服務器上運行,則頁面將重定向到 permalink。

這個 hook 將返回:

  • state:初始狀態將是我們傳遞給 initialState 的值。
  • formAction:一個將傳遞給表單操作的操作。此操作的返回值將在狀態中可用。

案例展示

import { useFormState} from 'react-dom';

const FormState = () => {
    const submitForm = (prevState, queryData) => {
        const name =  queryData.get("username");
        console.log(prevState); // 上一次的from 的state 
        if(name === '柒八九'){
            return {
                success: true,
                text: "前端開發者"
            }
        }
        else{
            return {
                success: false,
                text: "Error"
            }
        }
    }
    const [ message, formAction ] = useFormState(submitForm, null)
    return <form action={formAction}>
        <label>用戶名</label>
        <input type="text" name="username" />
        <button>提交</button>
        {message && <h1>{message.text}</h1>}
    </form>
}

export default FormState;

讓我們簡單解釋一下發生了啥

  • submitForm 是負責表單提交的方法。這是一個 Action。
  • 在 submitForm 中,我們正在檢查表單的值。

prevState:初始狀態將為 null,之后它將返回表單的 prevState。

queryData:用于獲取此次操作中from表單中對應key的值

useOptimistic() hook

useOptimistic 也新發布的Hook,它允許我們在異步操作時顯示不同的狀態。

這個 hook 將幫助增強用戶體驗,并應該導致更快的響應。這對于需要與服務器交互的應用程序非常有用。

語法

以下是 useOptimistic hook 的語法:

const [ optimisticX, addOptimisticX] = useOptimistic(state, updatefn)

例如,當響應正在返回時,我們可以顯示一個「optimistic狀態」,以便讓用戶獲得即時響應。一旦服務器返回實際響應,optimistic狀態將被替換。

案例展示

import { useOptimistic, useState } from "react";

const Optimistic = () => {
  const [messages, setMessages] = useState([
    { text: "初始化信息", sending: false, key: 1 },
  ]);
  
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true,
      },
    ]
  );

  async function sendFormData(formData) {
    const sentMessage = await fakeDelayAction(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }

  async function fakeDelayAction(message) {
    await new Promise((res) => setTimeout(res, 1000));
    return message;
  }

  const submitData = async (userData) => {
    addOptimisticMessage(userData.get("username"));

    await sendFormData(userData);
  };

  return (
    <>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={submitData}>
        <h1>OptimisticState Hook</h1>
        <div>
          <label>Username</label>
          <input type="text" name="username" />
        </div>
        <button type="submit">Submit</button>
      </form>
    </>
  );
};

export default Optimistic;
  • fakeDelayAction 模擬一個異步操作。
  • submitData 是 action。這個方法負責表單提交。這也可以是 async 的。
  • sendFormData 負責將表單發送到 fakeDelayAction
  • 設置默認狀態。messages 將用作 useOptimistic() 的輸入,并將返回 optimisticMessages。
const [messages, setMessages] = useState([{ text: "初始化信息", sending: false, key: 1 },]);

在 submitData 內部,我們使用 addOptimisticMessage。這將添加表單數據,以便在 optimisticMessage 中可用。我們將使用此數據在 UI 中顯示消息:

{optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}

其實,我們以后在處理類似Form表單狀態時,可以配合Action/useOptimistic/useFormState/useFormState進行狀態的各種流轉處理。

圖片圖片


Reference

[1]React 編譯器_youtube地址:https://youtu.be/kjOacmVsLSE?si=dqCjg0_9x2hOB8BF

[2]React Forget的基本介紹:https://dev.to/usulpro/how-react-forget-will-make-react-usememo-and-usecallback-hooks-absolutely-redundant-4l68

[3]Lit:https://lit.dev/

[4]SEO教程:https://moz.com/beginners-guide-to-seo

[5]react-helmet:https://www.npmjs.com/package/react-helmet

責任編輯:武曉燕 來源: 前端柒八九
相關推薦

2024-04-28 09:01:06

React 19更新前端

2024-04-03 08:47:58

React服務端組件Actions

2019-11-06 16:33:29

Ignite微軟技術

2020-07-22 08:58:56

C++特性函數

2021-10-22 15:45:32

開發技能React

2022-09-21 18:41:15

英偉達顯卡

2025-01-15 10:02:09

APIVueDOM

2021-04-16 16:21:02

鴻蒙HarmonyOS應用開發

2024-12-06 08:00:51

2010-02-03 13:25:34

云計算

2022-11-29 07:48:16

2024-11-25 16:41:20

2015-03-05 09:26:28

網絡中立命名數據網絡FDD

2021-01-28 16:58:12

數字貨幣加密貨幣區塊鏈

2021-06-16 06:05:25

React18React

2014-06-23 09:04:56

Docker

2014-12-08 09:55:33

Android 5.0Google

2020-10-09 08:38:14

Python 3.9Python開發

2015-12-29 13:32:41

2021-11-16 14:21:02

React 開發 Beta
點贊
收藏

51CTO技術棧公眾號

青娱乐精品在线| 国色天香一区二区| 久久国产精品72免费观看| 日韩精品一区二区三区中文不卡| 日韩av手机在线观看| 亚洲性图第一页| 一广人看www在线观看免费视频| 日韩在线麻豆| 亚洲第一狼人社区| 91九色在线观看| 伊人久久久久久久久久久久久久| 欧美电影免费看| 91久色porny| 欧美一区在线直播| 亚洲成人av免费在线观看| 久久99亚洲网美利坚合众国| 国产原创一区二区三区| 日韩最新中文字幕电影免费看| 日本新janpanese乱熟| 外国精品视频在线观看| 亚洲美女色禁图| 亚洲黄色在线看| 免费国产a级片| 欧洲成人一区二区三区| 黄色成人在线网址| 这里只有精品在线播放| 99re精彩视频| 成人日批视频| 国产伦精一区二区三区| 欧美成人手机在线| 香蕉视频xxx| se01亚洲视频| 国产精品色眯眯| 91精品久久久久久久久久久久久久| 久久久精品人妻一区二区三区| 亚洲黄色免费av| 国产亚洲成aⅴ人片在线观看| 91国自产精品中文字幕亚洲| 久久久久久久久久久国产精品| 亚洲精品成人图区| 亚洲午夜精品在线| 欧美激情论坛| 91免费视频播放| 一区二区蜜桃| 亚洲国产欧美一区二区丝袜黑人| 天天色天天综合网| 国内老司机av在线| 久久免费看少妇高潮| 国产精品视频免费在线| 成人免费毛片东京热| 91夜夜蜜桃臀一区二区三区| 欧美日韩另类字幕中文| 亚洲成人一区二区三区| 精品国自产拍在线观看| 午夜一区在线| 日韩最新在线视频| 国产主播av在线| 97久久超碰| 日韩精品一区二区三区四区视频| 97人人爽人人| 精品国产三级| 欧美日韩中文字幕| 杨幂一区欧美专区| 天天操天天射天天舔| 久久精品理论片| 韩国19禁主播vip福利视频| 18禁一区二区三区| 日韩精品一区二区三区中文字幕| 五月天欧美精品| 亚洲在线不卡| 日本高清视频在线播放| 国产精品乱码久久久久久| 一本一道久久久a久久久精品91| 秋霞影院午夜丰满少妇在线视频| 成人精品免费看| 国产日产亚洲精品| 国产绿帽一区二区三区| 麻豆精品网站| 欧美精品videossex88| 99国产精品无码| 网红女主播少妇精品视频| 精品调教chinesegay| 香蕉视频在线观看黄| 69堂免费精品视频在线播放| 亚洲天堂精品视频| 蜜桃狠狠色伊人亚洲综合网站| 国产三级在线观看视频| 国产精品1区2区3区在线观看| 国产国产精品人在线视| 香蕉免费毛片视频| 欧美三级免费| 久久黄色av网站| 波多野吉衣中文字幕| 精品麻豆剧传媒av国产九九九| 日韩欧美成人一区| 亚洲AV无码片久久精品| 天天射成人网| 一区二区三区动漫| 久久精品国产亚洲av久| 日韩一区欧美| 这里只有精品视频| 久久久久久激情| 亚洲91精品| 久久久av网站| 69成人免费视频| 国产精品多人| 国产精品高潮视频| 波多野结衣激情视频| 久久久999| 亚洲精品免费av| 999国产精品视频免费| 97久久超碰国产精品电影| 国产伦精品一区二区三区照片| 成人黄色在线观看视频| xnxx国产精品| 黄色a级片免费看| 欧美一卡二卡| 欧美性猛交xxxx黑人交| 午夜久久久精品| 日韩成人综合网| 欧美日韩美女一区二区| 爱豆国产剧免费观看大全剧苏畅 | 一区二区三区日韩欧美| 在线亚洲美日韩| av基地在线| 中文字幕欧美一区| 9l视频自拍9l视频自拍| 国产黄色在线网站| 欧洲精品在线观看| 手机在线国产视频| 自拍亚洲一区| 中文字幕一区二区三区电影| 欧美日韩综合在线观看| 噜噜噜久久亚洲精品国产品小说| 国产高清自拍99| 青青久草在线| 国产免费成人在线视频| 亚洲欧洲精品在线| 日韩免费福利视频| 亚洲精品久久久一区二区三区 | 不卡一区在线观看| 亚洲成人动漫在线| 亚洲精品大片| 日韩小视频网址| 在线观看日韩一区二区| 国产在线精品免费| 亚洲午夜高清视频| 韩国精品视频在线观看| 日韩一区二区三区四区 | 91成人精品在线| 亚洲国产小视频在线观看| 69av.com| 国产盗摄一区二区三区| 欧美综合77777色婷婷| 99视频在线观看地址| 91久久线看在观草草青青| 欧美在线a视频| 日韩欧美影院| 欧美亚洲一级片| 少妇一级淫片免费看| 偷拍日韩校园综合在线| 亚洲男人在线天堂| 久久国产日韩| 亚洲一区二区三区免费观看| 99国内精品久久久久| 亚洲第一色在线| 亚洲av成人无码一二三在线观看| 91精品电影| 97人人澡人人爽| 俄罗斯一级**毛片在线播放| 日韩成人中文电影| 欧美三级网站在线观看| 国产一区在线视频| 蜜臀av性久久久久蜜臀av| 俄罗斯一级**毛片在线播放| 亚洲精品成人久久电影| 亚洲中文一区二区| 福利电影一区二区三区| 亚洲人成人77777线观看| 国产精品国产三级在线观看| 亚洲一级片在线看| 九九热精彩视频| 蜜芽一区二区三区| 国产福利不卡| 忘忧草在线日韩www影院| 一本一本久久a久久精品牛牛影视 一本色道久久综合亚洲精品小说 一本色道久久综合狠狠躁篇怎么玩 | 91精品午夜视频| 亚洲AV无码片久久精品| 久久电影网站中文字幕| 国产黄色激情视频| 国产成人短视频在线观看| 性色av一区二区三区免费| 青春有你2免费观看完整版在线播放高清 | 黄页网站在线观看视频| avtt久久| 91国产精品电影| 免费在线观看av片| 亚洲精品456在线播放狼人| 波多野结衣一区二区三区在线| 亚洲欧美日韩电影| 伊人色在线观看| 欧美日韩在线网站| 国产97在线亚洲| 成人在线直播| 亚洲三级av在线| 伊人久久久久久久久久久久| 亚洲女人****多毛耸耸8| 极品白嫩丰满美女无套| 亚洲美女少妇无套啪啪呻吟| 亚洲欧美日韩国产成人综合一二三区| 自拍偷拍欧美日韩| 欧美伊久线香蕉线新在线| 国产黄色在线网站| 自拍偷拍亚洲一区| 天堂在线一二区| 日韩欧美一二三区| 在线免费看91| 91国偷自产一区二区开放时间 | 国产高清一区二区三区| 欧美国产视频| 国产精品久久久精品| 国产精品25p| 亚洲加勒比久久88色综合| 国产又黄又粗又长| 一区二区在线观看不卡| 日韩乱码人妻无码中文字幕久久| 高清久久久久久| 亚洲成人手机在线观看| 麻豆精品在线看| 日本爱爱免费视频| 亚州av乱码久久精品蜜桃| 欧美日韩精品久久| 欧美日韩一区二区三区不卡视频| 欧美在线视频网| 二人午夜免费观看在线视频| 欧美老女人在线| 欧美精品久久久久性色| 国产精品久久久久久久裸模| 精品人妻一区二区三区免费| 蜜桃免费网站一区二区三区| 亚洲人成色77777| 亚洲国产精品91| 亚洲一卡二卡区| 成人综合专区| 99精品在线直播| 亚洲福利影院| 777精品视频| 538视频在线| 在线丨暗呦小u女国产精品| 久草在线免费福利资源| 欧美精品18+| 96亚洲精品久久久蜜桃| 欧美另类z0zxhd电影| 91久久国语露脸精品国产高跟| 欧美性生活一区| 亚洲天堂中文在线| 欧美男女性生活在线直播观看| 91成人国产综合久久精品| 欧美日韩国产精品成人| 国产女人爽到高潮a毛片| 欧美一级欧美三级| 好吊色一区二区| 欧美猛男gaygay网站| 国产一区二区女内射| 日韩午夜在线观看| 欧美 日韩 人妻 高清 中文| 日韩成人高清在线| 狠狠狠综合7777久夜色撩人| 最近2019年手机中文字幕| 欧美熟女一区二区| 日韩激情av在线播放| 国产一级在线| 精品久久久av| 黄频免费在线观看| 国产精品久久久久久久久久尿| 中文幕av一区二区三区佐山爱| 北条麻妃高清一区| 亚洲警察之高压线| 一区二区精品在线观看| 狠狠爱综合网| 少妇高清精品毛片在线视频| 久88久久88久久久| 少妇精品无码一区二区三区| 国产自产2019最新不卡| 色综合久久久无码中文字幕波多| 成人听书哪个软件好| 91欧美一区二区三区| 99久久精品免费看国产| 麻豆免费在线观看视频| 97se亚洲国产综合在线| 国精产品视频一二二区| 亚洲成年人影院| 中文字幕乱码人妻二区三区| 91国产丝袜在线播放| 国产男男gay体育生白袜| 亚洲精品suv精品一区二区| 欧美边添边摸边做边爱免费| 97人人模人人爽人人喊中文字| 97欧美成人| 好吊色欧美一区二区三区视频 | 日韩高清不卡一区二区| 精品国产免费av| 国产精品久久777777毛茸茸| 青青草国产精品视频| 日韩成人dvd| 国产麻豆剧传媒精品国产av| 国产精品久久毛片av大全日韩| 欧美日韩中文视频| 亚洲国产中文字幕| 亚洲视频久久久| 亚洲人成人99网站| 国内在线视频| 91中文字幕在线| 日韩精品免费一区二区三区| 无码人妻丰满熟妇区96| 久久激情婷婷| av电影在线播放| 久久先锋影音av鲁色资源网| 高h视频免费观看| 色欧美日韩亚洲| 日韩中文字幕影院| 欧美成人一二三| 先锋影音网一区二区| 日韩一区国产在线观看| 欧美a级片视频| 波多野结衣与黑人| 蜜臀av一区二区在线免费观看| 艳妇乳肉亭妇荡乳av| 亚洲综合在线视频| 国产高清中文字幕| 精品免费国产一区二区三区四区| 午夜激情在线视频| 一本色道久久综合狠狠躁篇怎么玩| 1024在线看片你懂得| 国产精品9999久久久久仙踪林| 久久久久亚洲| 亚洲欧美日韩网站| 亚洲人成网站影音先锋播放| 亚洲影院一区二区三区| 日韩中文字幕在线视频| 香蕉久久一区| 精品91一区二区三区| 韩国成人精品a∨在线观看| 伊人久久一区二区三区| 夜夜揉揉日日人人青青一国产精品 | 国产在线精品日韩| 欧美日韩中文一区二区| 黑森林福利视频导航| 黄页网站大全一区二区| 小向美奈子av| 91麻豆精品国产自产在线观看一区 | 一区二区三区精密机械公司| 国产成人a人亚洲精品无码| 亚洲精品国产品国语在线| 成全电影大全在线观看| 国产主播一区二区三区四区| 国产亚洲亚洲| 蜜桃无码一区二区三区| 欧美日韩在线观看一区二区 | 亚洲男人天堂视频| 毛片在线播放a| 亚洲a区在线视频| 亚洲高清电影| 中文字幕第22页| 一区二区三区小说| 黄色三级网站在线观看| 欧美一区二粉嫩精品国产一线天| 九一亚洲精品| www.av毛片| 91免费在线播放| 这里只有精品999| 久久久av一区| 嫩草国产精品入口| 国产天堂在线播放| 亚洲色图一区二区| 狠狠躁夜夜躁av无码中文幕| 日本精品久久久| 色喇叭免费久久综合| 亚洲精品乱码久久久久久9色| 欧美性猛交xxxxx水多| 色网站在线看| 国产亚洲二区| 久久国产精品色| 国产无精乱码一区二区三区| 亚洲人成网站在线播| 国产精品1区| 国产资源在线视频| 亚洲欧洲三级电影| 五月婷婷丁香花| 91久久在线观看| 97精品国产福利一区二区三区| 国产成人av免费观看| 色欧美片视频在线观看在线视频| www.久久ai| 欧美激情第六页| 成人一级片在线观看| 国产一级片免费在线观看| 欧美二区乱c黑人| 一区二区三区免费在线看| 成年人免费在线播放|