🎁

React Conf 2021 個人的まとめ

2021/12/10に公開
2

React Confとは

これ
https://conf.reactjs.org/

追記:YouTubeにアーカイブがそれぞれ上がってたので貼っておきます!
YouTubeのvideoIDが不正ですhttps://www.youtube.com/channel/UC1hOCRBN2mnXgN5reSoO3pQ

注意

まとめたのはKeyNoteと React 18 for app Developerのとこだけです
あとReact Nativeのところは端折ってます。
面白そうなのがあればまた追記して行きます。

はじめに

ReactのAPIはプログラミングではなく、「design principles」(設計原則)に根差している。
だから、最近のデザインツールがReactのコードを吐き出したりするのも不思議じゃない。
Reactを使えばデザイナーと同じ言葉でプログラマーが会話をできるということだ。
真のUXとは開発体験を犠牲にせずとも済むものののはずだ。

React Suspense

React Suspenseがやりたいこと

「ネットワークを介したデータの受け取りをpropsやstateと同じくらい簡単にしたい」
つまりもっと宣言的にしたい!ってこと

Reactのコンポーネントは
上から読めばコンポーネントが何をしたいのかわかる、とても宣言的である。
Loadingが入ってもそれは言える。

function List({pageId}) {
    const [items, isLoading] = useData(pageId)
    if(isLoading) {
        return <Spinner />
    }
    return item[pageId].map(item => <li>{ item }</li>)
}

でも以下のようにisLoadingという状態をこのコンポーネントから追放したらもっと宣言的になる

function List({pageId}) {
    const items = useData(pageId)
    return items[pageId].map(item => <li>{ item }</li>)
}

これを実現したのがSuspense

<Suspense fallback={<Spinner />}>
    <List pageId={pageId} />
</Suspense>

Suspneseは子コンポーネントのデータフェッチが完了するまでfallbackを返し、完了したら子を返す。
つまり、以下の部分を今後はReactとそれに対応するデータフェッチライブラリがやってくれるってこと。

    if(isLoading) {
        return <Spinner />
    }

何が嬉しいか

  1. 子コンポーネントがより宣言的になる
  2. 僕らはloadingを束ねて複数のloadingを管理したりすることがなくなる
// before
const isLoading = userLoading || postLoading
if(isLoading) {
  return <Spinner />
}
return <>
  <Post postId={postId} />
  <User userId={userId} />
</>

// after
<Suspense fallback={<Spinner />}>
  <Post postId={postId} />
  <User userId={userId} />
</Suspense>

18になってどうなるか

まずはこれらがrelayに対応する形で実装され、SWRやreact queryなどはこの後徐々に対応という形になりそう。
SSRでもSuspnenseが動くように。

Concurrent Features

旧Concurrent Modeが名前が変わった。
今まではConcurrent Modeを適用すると全てのコンポーネントにそれらがすぐに適用されたがそうでなくなった。
段階的な導入が可能になった。

Server Components

安定リリースには含まれないが、マイナーリリースで出せたら出したいらしい

Automatic Batching

Reactは状態を更新する関数があった場合に、関数内の全ての処理が終わってからコンポーネントを一回だけ再レンダリングする。

const handleClick = () => {
    setFetching(true) // ここではレンダリングされない
    setError(null)  // ここが関数の最後なのでレンダリングされる
}

しかし18以前はイベントハンドラから起こる更新以外はバッチ処理できていなかった。

fetch('/api').then(() => {
    setFetching(true) // 1回目レンダリング
    setError(null)  // 2回目レンダリング
})

これがちゃんと最後に一回だけレンダリングされるようになった。
つまりパフォーマンス改善。

Suspense on Server

18以前

SSRは「ALL or Nothing」だった。
つまりページ内の全てをSSRするか、しないかの二択しかなかった。
これだとある特定のコンポーネントがすごく重いせいで、ページ全体が重くなってしまう。

18になってどうなるか

SSR時にSuspenseが機能することで、重いコンポーネントにSuspenseをつけて一旦スピナーを表示させることができるようになり、特定のコンポーネントがすごく重いせいで、ページ全体が重くなってしまうのを回避できる。
データの取得が終わればサーバーはスピナーの代わりに子コンポーネントを返す。(クライアントでの挙動と同じ)
これらがJS,Reactが読み込まれる前にできるのでユーザーはいち早くコンテンツに到達できる。

アップグレードの仕方

  1. 18に上げる
  2. ReactDOM.renderをReactDOM.createRootに変える
// before
let container = document.getElementById('app')
ReactDOM.render(<App>, container)

// after
let container = document.getElementById('app')
let root = ReactDOM.createRoot(container)
root.render(<App />)

これだけ!
ほとんどのアプリはこれで普通に動く。

感想

個人的に今年は「宣言的」という言葉によく触れた年であった気がする。
一昨年くらいにReact Hooksが出てきたときに「宣言的」という言葉に初めて触れ、今年になってようやくその意味がわかってきて、さらにこのReact Confでなぜそれが大事なのかわかった。
Reactが目指しているのは、UX(ユーザー体験)とDX(開発体験)の調和と躍進であり、デザインとプログラミングの統合だと感じた。
それには、デザイナーとプログラマーが同じ言語で話す必要があり、例えばコンポーネントの見た目の話をするときに、状態の管理の話をプログラマーが持ち出すのはあまり良くないだろう。
そういうのをReactはなくしていきたいんであって、僕らはそういうライブラリを使うんだから、僕らもこのライブラリの思想に対して真摯に向き合わなきゃなと思った。
具体的にはUXの勉強頑張ろうって思った。
良いお年を。

Discussion

nishiurahirokinishiurahiroki

とても参考になりました。ありがとうございます。

「アップグレードの仕方」欄下部の実装例最終行ですが、rootroomにタイポしている気がします。

よだかよだか

本当ですね…
修正いたしました!
ご指摘ありがとうございます!