React 19 が出たらしい
Nextのおかげで見慣れてる更新が多い一方で、まだふわっとしかわかってないことも多い。
ただ、16.8 以来の変わりような気がしてる
手元で動かしながらやるか
ということでupgrade guide
This beta release is for libraries to prepare for React 19. App developers should upgrade to 18.3.0 and wait for React 19 stable as we work with libraries and make changes based on feedback.
一旦は18.3で我慢しとけよとも書いてある
こういうことだわな
WARN Issues with peer dependencies found
.
├─┬ @storybook/addon-essentials 8.0.8
│ └─┬ @storybook/addon-controls 8.0.8
│ └─┬ @storybook/blocks 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ @storybook/components 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ @radix-ui/react-slot 1.0.2
│ │ ├── ✕ unmet peer react@"^16.8 || ^17.0 || ^18.0": found 19.0.0-beta-94eed63c49-20240425
│ │ └─┬ @radix-ui/react-compose-refs 1.0.1
│ │ └── ✕ unmet peer react@"^16.8 || ^17.0 || ^18.0": found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ @storybook/icons 1.2.9
│ │ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ └── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ @storybook/theming 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
├─┬ @storybook/addon-links 8.0.8
│ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
├─┬ @storybook/nextjs 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ @storybook/preset-react-webpack 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ @storybook/react 8.0.8
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ @storybook/react-dom-shim 8.0.8
│ │ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ └── ✕ unmet peer react-dom@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ react-element-to-jsx-string 15.0.0
│ ├── ✕ unmet peer react@"^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └── ✕ unmet peer react-dom@"^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
├─┬ @testing-library/react 15.0.2
│ ├── ✕ unmet peer react@^18.0.0: found 19.0.0-beta-94eed63c49-20240425
│ └── ✕ unmet peer react-dom@^18.0.0: found 19.0.0-beta-94eed63c49-20240425
├─┬ @mantine/core 7.8.0
│ ├── ✕ unmet peer react@^18.2.0: found 19.0.0-beta-94eed63c49-20240425
│ ├── ✕ unmet peer react-dom@^18.2.0: found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ react-number-format 5.3.4
│ │ ├── ✕ unmet peer react@"^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ └── ✕ unmet peer react-dom@"^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ react-remove-scroll 2.5.9
│ │ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ ├─┬ react-remove-scroll-bar 2.3.6
│ │ │ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ │ └─┬ react-style-singleton 2.2.1
│ │ │ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ ├─┬ use-callback-ref 1.3.2
│ │ │ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ │ └─┬ use-sidecar 1.1.2
│ │ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ react-textarea-autosize 8.5.3
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ ├─┬ use-composed-ref 1.3.0
│ │ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ use-latest 1.2.1
│ ├── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
│ └─┬ use-isomorphic-layout-effect 1.1.2
│ └── ✕ unmet peer react@"^16.8.0 || ^17.0.0 || ^18.0.0": found 19.0.0-beta-94eed63c49-20240425
├─┬ next 14.2.1
│ ├── ✕ unmet peer react@^18.2.0: found 19.0.0-beta-94eed63c49-20240425
│ └── ✕ unmet peer react-dom@^18.2.0: found 19.0.0-beta-94eed63c49-20240425
└─┬ @mantine/hooks 7.8.0
└── ✕ unmet peer react@^18.2.0: found 19.0.0-beta-94eed63c49-20240425
Errors in render are not re-thrown
初っ端からピンときてない
Removed deprecated React APIs
Removed deprecated React DOM APIs
知らんやつか、知ってても普段触らんやつばっかやった
Deprecated: element.ref
あ、これは気にするね
When double rendering in Strict Mode in development, useMemo and useCallback will reuse the memoized results from the first render during the second render. Components that are already Strict Mode compatible should not notice a difference in behavior.
Strict Mode 微修正
UMD builds removed
esmに移行
ref cleanups required
うーんピンときてないかも
refがよくわかってない説
A long-time complaint of how TypeScript and React work has been useRef. We’ve changed the types so that useRef now requires an argument. This significantly simplifies its type signature. It’ll now behave more like createContext.
This now also means that all refs are mutable. You’ll no longer hit the issue where you can’t mutate a ref because you initialised it with null:
useRef still has a convenience overload for useRef<T>(null) that automatically returns RefObject<T | null>. To ease migration due to the required argument for useRef, a convenience overload for useRef(undefined) was added that automatically returns RefObject<T | undefined>.
これは、はい、あざす
A long-time request is to remove the global JSX namespace from our types in favor of React.JSX. This helps prevent pollution of global types which prevents conflicts between different UI libraries that leverage JSX.
そういうこともあるか
Better useReducer typings
useReducer<React.Reducer<State, Action>>(reducer)
って書いたことないからピンと来てないな?相変わらず const reducer = (state: State, action: Action) => state;
でいいのよね?
What’s new in React 19
In React 19, we’re adding support for using async functions in transitions to handle pending states, errors, forms, and optimistic updates automatically.
The async transition will immediately set the isPending state to true, make the async request(s), and switch isPending to false after any transitions. This allows you to keep the current UI responsive and interactive while the data is changing.
transitionがasyncを受け付けるようになり、直観的なwaiting表現ができるようになった
const handleSubmit = async () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect("/path");
})
};
By convention, functions that use async transitions are called “Actions”.
らしい。
<form> elements now support passing functions to the action and formAction props.
も気になる
おそらく今回の大トロ
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
}
);
拾ってきた
export function useActionState<State>(
action: (state: Awaited<State>) => State | Promise<State>,
initialState: Awaited<State>,
permalink?: string,
): [state: Awaited<State>, dispatch: () => void, isPending: boolean];
export function useActionState<State, Payload>(
action: (state: Awaited<State>, payload: Payload) => State | Promise<State>,
initialState: Awaited<State>,
permalink?: string,
): [state: Awaited<State>, dispatch: (payload: Payload) => void, isPending: boolean];
React.useActionState was previously called ReactDOM.useFormState in the Canary releases, but we’ve renamed it and deprecated useFormState.
useFormState使ってたところを改修しなきゃだ
型としては State | Promise<State>
だけど、Successの場合はaction内で処理書けちゃうからerrorだけ返してるのか。なんかいびつな気もする?
if (error) {
// You can return any result of the action.
// Here, we return only the error.
return error;
}
// handle success
てかerrorの場合も処理は書けばいいか
なんか、パッと見Result型のStateを返すと良いかなと思ったけど、そうでもないかな
見とくか...
optional permalink: A string containing the unique page URL that this form modifies. For use on pages with dynamic content (eg: feeds) in conjunction with progressive enhancement: if fn is a server action and the form is submitted before the JavaScript bundle loads, the browser will navigate to the specified permalink URL, rather than the current page’s URL. Ensure that the same form component is rendered on the destination page (including the same action fn and permalink) so that React knows how to pass the state through. Once the form has been hydrated, this parameter has no effect.
わかりそうで一部わからんかも
うーん、initialStateが必須になってたり、isPendingが返ってきてなかったりと、噛み合わないところがあるな?
手元は
拾ってきた
の通り
これNot Foundになるな
New hook: useOptimistic
これなー、ちょっとむずいよね
本丸のStateは親のもので、propsで受け取っといて、optimistic state は子供でもって、表示だけ上書きする。
function ChangeName({currentName, onUpdateName}) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName);
const updatedName = await updateName(newName);
onUpdateName(updatedName);
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<p>
<label>Change Name:</label>
<input
type="text"
name="name"
disabled={currentName !== optimisticName}
/>
</p>
</form>
);
}
useねー
これもちょっとgame変わるのかなー
キャッシュ周りのこと考えると結局tanstackなどのライブラリを使うことになるのかなー
function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
use does not support promises created in render.
んー、これもふわっとしかわかってないな
In the future we plan to support more ways to consume resources in render with use.
useはまだまだ発展途上って感じかなー
自分の理解度も浅いからもうちょい様子見かも
This separate environment is the “server” in React Server Components. Server Components can run once at build time on your CI server, or they can be run for each request using a web server.
ちょっと前に物議を醸したやつだw
ref as a prop
PropsWithRef みたいな形が提供されてるかなと思ったら見つからなかった
Diffs for hydration errors
あ〜これめっちゃたすかる
<Context> as a provider
いいとおもいます
てかProviderにもConsumerにもなるContextオブジェクトどんな実装やろか
useで何が取り出されているんやろ
extends Providerらしい
interface Context<T> extends Provider<T> {
Provider: Provider<T>;
Consumer: Consumer<T>;
/**
* Used in debugging messages. You might want to set it
* explicitly if you want to display a different name for
* debugging purposes.
*
* @see {@link https://legacy.reactjs.org/docs/react-component.html#displayname Legacy React Docs}
*/
displayName?: string | undefined;
}
useはこう。単にContextが来たらContext.Consumer取り出すようにしているだけか
export type Usable<T> = Thenable<T> | Context<T>;
export function use<T>(usable: Usable<T>): T;
Previously, React would call ref functions with null when unmounting the component. If your ref returns a cleanup function, React will now skip this step.
In future versions, we will deprecate calling refs with null when unmounting components.
ref周りちょっと注意かもな
次使う場面あったらちゃんとドキュメント読もう
Support for Document Metadata
おおっ?これすごい変化だな
便利やけどキモいって言われそう
あと挿入順も気になるな
Support for stylesheets
これちょっとおもろいな。Suspenseがここにつながるとは思ってなかった。
In React 19 we’ve included better support for async scripts by allowing you to render them anywhere in your component tree, inside the components that actually depend on the script, without having to manage relocating and deduplicating script instances.
すごいな、えらいね
Support for preloading resources
最適化の手法がひとつ増えたねー
Compatibility with third-party scripts and extensions
悩み減りそう
Better error reporting
これもたすかる
Support for Custom Elements
Web Components活性化?