<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React 19 即將推出的 4 個(gè)全新 Hooks,很實(shí)用!

          共 10246字,需瀏覽 21分鐘

           ·

          2024-04-10 13:41

          近日,React 團(tuán)隊(duì)成員在社交平臺(tái)表示,團(tuán)隊(duì)正在開(kāi)發(fā) React v19 版本,并且沒(méi)有計(jì)劃發(fā)布 v18.3 版本。

          63a7810912af3baae055a52f62263b01.webpReact 19 預(yù)計(jì)將推出 4 個(gè)全新 Hooks,這些 Hooks 主要關(guān)注 React 中的兩個(gè)痛點(diǎn):數(shù)據(jù)獲取表單。 這些 Hooks 目前在 React 預(yù)覽版本中作為實(shí)驗(yàn)性 API 提供,預(yù)計(jì)會(huì)成為 React 19 的一部分,但是最終發(fā)布之前,API 可能會(huì)有所變化。

          新的 Hooks 包括:

          • use

          • useOptimistic

          • useFormState

          • useFormStatus

          use

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

          
           
          const value = use(resource);

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

          use(Promise)

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

          
           
          import { use } from 'react';

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

          下面來(lái)看一個(gè)簡(jiǎn)單的例子:

          
           
          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(() => {
          // 每次刷新時(shí)添加一個(gè)標(biāo)題
          news.unshift(faker.lorem.sentence());
          resolve(news);
          }, 1000)
          );

          const NewsContainer = ({ newsPromise }) => (
          <Suspense fallback={<p>請(qǐng)求中...</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í),都會(huì)先顯示“請(qǐng)求中...”,請(qǐng)求到數(shù)據(jù)后進(jìn)行展示:

          43ca2f820281e4e0557216d0a7d5dcf1.webp官方文檔中,關(guān)于 <Suspense> 有一個(gè)警告:

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

          在新版本中,use 可能就是用于與 Suspense 集成數(shù)據(jù)源的官方 API。

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

          use(Context)

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

          
           
          import { use } from 'react';

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

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

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

          useOptimistic

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

          
           
          import { useOptimistic } from 'react';

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

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

          下面來(lái)看一個(gè)添加購(gòu)物車的例子:

          
           
          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) {
          // 捕獲錯(cuò)誤
          }
          };

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

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

          const Cart = ({ cart }: { cart: Item[] }) => {
          if (cart.length == 0) {
          return null;
          }
          return (
          <>
          購(gòu)物車:
          <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高級(jí)程序設(shè)計(jì)"
          addToCart={addToCart}
          optimisticAddToCart={optimisticAddToCart}
          />
          </>
          );
          };

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

          e0ccd9fb73385121850021baf13ccbb6.webp

          useFormState

          在介紹這個(gè) Hook 之前,先來(lái)看以下這個(gè) Hook 使用的背景。

          <form>

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

          
           
          <form action={handleSubmit} />

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

          ?? Warning: Invalid value for prop action on <form> 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無(wú)效。要么從元素中刪除它,要么傳遞一個(gè)字符串或數(shù)字值以將其保留在 DOM 中。

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

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

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

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

          看完這個(gè)新功能,下面就來(lái)看看這一部分要介紹的新 Hook:useFormState。

          useFormState

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

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

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

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

          
           
          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">添加到購(gòu)物車</button>&nbsp;
          {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高級(jí)程序設(shè)計(jì)"
          addToCart={addToCart}
          />
          </>
          );
          };

          效果如下:

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

          useFormStatus

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

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

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

          • pending:布爾值。如果為 true,則表示父級(jí) <form> 正在等待提交;否則為 false。

          • data:包含父級(jí) <form> 正在提交的數(shù)據(jù);如果沒(méi)有進(jìn)行提交或沒(méi)有父級(jí) <form>,它將為 null。

          • method:字符串,可以是 'get' 或 'post'。表示父級(jí) <form> 使用 GET 或 POST HTTP 方法 進(jìn)行提交。默認(rèn)情況下,<form> 將使用 GET 方法,并可以通過(guò) method 屬性指定。

          • action:一個(gè)傳遞給父級(jí) <form>action 屬性的函數(shù)引用。如果沒(méi)有父級(jí) <form>,則該屬性為 null。如果在 action 屬性上提供了 URI 值,或者未指定 action 屬性,status.action 將為 null

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

          
           
          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) {
          // 捕獲錯(cuò)誤
          }
          };

          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">
          添加到購(gòu)物車
          </button>
          );
          };

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

          const Cart = ({ cart }: { cart: Item[] }) => {
          if (cart.length == 0) {
          return null;
          }
          return (
          <>
          購(gòu)物車:
          <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高級(jí)程序設(shè)計(jì)"
          addToCart={addToCart}
          />
          </>
          );
          };

          添加購(gòu)物車時(shí)效果如下:

          f823ccbc16b8612fb2dea62b2e4687ab.webp

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

          往期推薦

          盤(pán)點(diǎn) 2023 年前端大事件

          都 2024 年了,該如何搭建新的 React 項(xiàng)目?

          太失望了!前端社區(qū)對(duì) React 的抱怨越來(lái)越多...

          npm 淘寶鏡像到期了,盡快切換~

          Prettier + ESLint + Rust = ??  快,真是太快了!

          78k Star!爆火的高質(zhì)量前端工具集,超實(shí)用!

          推薦 12 個(gè) yyds 的開(kāi)源鴻蒙實(shí)戰(zhàn)項(xiàng)目


          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级不免福利在线 | 免费A片在线播放 | 逼特逼在线观看视频 | 无码视频在线看 | 青青草原网站在线观看 |