Closed5
memo @240203*
React 19 hooks
use(Promise)
use
の中に非同期処理などの非同期な関数を入れることによってその解決まで行ってくれる。
そもそもuseEffect
を使ってフェッチするというのはバッドプラクティスというか
本来やっていいけれどもuseEffect
を使って適切に非同期処理を行うのはとても難しい。
use
があったらuseEffect
を使ってそれを行うよりもずっと簡単にできる。
import { use } from 'react';
function MessageComponent({ messagePromise }) {
const message = use(messagePromise);
// ...
}
従来はRSC
ならasync
await
を使ってデータをフェッチできたけれども、
クライアントコンポーネント
だと基本的にasync
コンポーネントにすることはできず、
useEffect
とかなにかしらの方法を使ってフェッチしないといけなかった。
でもuse
が出てきたおかげでちょっとしたデータのフェッチとかなら、
TanStack Query
とかも使わなくてよくなりそう。
use(Context)
Context
をuse
の中に入れることによってContext
の値を読み取れる。
これはuseContext
とまったく同じ。しかしループやif
などの条件文内で呼び出せる。
useContext
は使わないようになる。
import { use } from 'react';
function HorizontalRule({ show }) {
if (show) {
const theme = use(ThemeContext);
return <hr className={theme} />;
}
return false;
}
Form Actions
form
のaction
にformAction
と入れることによってformData
を直接取得できるようになる。
app.tsx
import { useState } from 'react';
const AddToCartForm = ({ id, title, addToCart }) => {
const formAction = async (formData) => {
try {
await addToCart(formData, title);
} catch (e) {
// show error notification
}
};
return (
<form action={formAction}>
<h2>{title}</h2>
<input type="hidden" name="itemID" value={id} />
<button type="submit">Add to Cart</button>
</form>
);
};
type Item = {
id: string;
title: string;
};
const Cart = ({ cart }: { cart: Item[] }) => {
if (cart.length == 0) {
return null;
}
return (
<>
Cart content:
<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'));
// simulate an AJAX call
await new Promise((resolve) => setTimeout(resolve, 1000));
setCart((cart: Item[]) => [...cart, { id, title }]);
return { id };
};
return (
<>
<Cart cart={cart} />
<AddToCartForm
id="1"
title="JavaScript: The Definitive Guide"
addToCart={addToCart}
/>
<AddToCartForm
id="2"
title="JavaScript: The Good Parts"
addToCart={addToCart}
/>
</>
);
};
useFormState
useFormState
によってform
の戻り値を取得できる。
import { useFormState } from 'react-dom';
import { action } from './action';
function MyComponent() {
const [state, formAction] = useFormState(action, null);
// ...
return <form action={formAction}>{/* ... */}</form>;
}
useFormStatus
useFormStatus
によってform
がいまどういう状態なのかを取得できる。
const { pending, data, method, action } = useFormStatus();
useOptimistic
useOptimistic
を使うことによってaction
の送信中にUIを楽観的に更新できる。
import { useOptimistic } from 'react';
function AppContainer() {
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value
},
);
}
Bonus: Async Transitions
React
のTransition API
を使うことによってUI をブロックせずに状態を更新できる。
たとえば、ユーザーの気が変わったら、以前の状態の変更をキャンセルできる。
function TabContainer() {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState('about');
function selectTab(nextTab) {
// instead of setTab(nextTab), put the state change in a transition
startTransition(() => {
setTab(nextTab);
});
}
// ...
}
このスクラップは2024/02/03にクローズされました