APIを作りながら進むGo中級者への道を読んだ

1 min read

Goは業務で使ってこなかったので覚えてはちょっと忘れてを繰り返し、Go言語の再々々入門ぐらいになりますが、時間があったので気になってた「APIを作りながら進むGo中級者への道」を読みました。

ブログAPIをつくるハンズオン形式で進める本になっていて、webAPIを作るときの基本になるような内容が詰まってました。

Go言語触るときにいつもHandleFunc, Handle, HandlerFunc, Handlerの違いが分からなくなって何だっけ?となっていたのですが、この本の「ミドルウェアによるロギング」の章ですっきり頭に入った気がします。

またレポジトリ層、サービス層、ハンドラ層など全体のアーキテクチャをみて可読性や効率を考えながらコードを書き進めていくので実際の業務に近いかたちのハンズオンだと感じました。テストコードも書いてくれているのでパッケージの使い方や実際のテストケースの考え方も参考になる。

引き続きキャッチアップしていきたい。

Continue reading →

Prismaのスキーマが分割できるようになった

2 min read

5月30日にPrismaのX(Twitter)から匂わせポストが来ていました。 https://x.com/prisma/status/1796131178421821508

上のポストでは今までのschema.prismaのようなファイルにスキーマが書かれているのではなくPost.prismaとUser.prismaといったファイルに分割されて記述されているのがわかります。

これ見た時についに来た!といった感じでより便利になりそうだなと思って眺めてました。

そして後日改めてポストとブログが投稿されました。 ポストは以下。 https://x.com/prisma/status/1798020268029599916

🗃️ Use one (or many!) Prisma schema files in Prisma ORM!

Prisma ORM version 5.15.0 ships with a new Preview feature allowing for a multi-file Prisma Schema.

Check out our announcement blog post 👇
http://prisma.io/blog/organize-your-prisma-schema-with-multi-file-support

公式のブログはこっち

http://prisma.io/blog/organize-your-prisma-schema-with-multi-file-support

数年前にスキーマを分割できたらいいのになぁと思ってなにか方法が無いか探してたときは、サードパーティー製のツールを使っていました。今後はそれが不要になりそうです。

サードパーティー製ツールの使い方をまとめてたZenn。 https://zenn.dev/pale_delphinium/articles/96397db45866b0

当時眺めてたissue。 https://github.com/prisma/prisma/issues/2377

今後は以下のディスカッションにフィードバックが集まってきそうなので引き続き注視していきたい。

https://github.com/prisma/prisma/discussions/24413

Continue reading →

React 19が来る

6 min read

React19 Betaがnpmで利用可能になったようです。

Actions

慣習で非同期遷移(async transitions)を使用する関数は "Actions" と呼ばれるとのこと。 Actionはデータの送信を自動的に管理してくれる。

  • 保留状態
  • 楽観的更新
  • エラー処理
  • フォーム

useTransition()

よくある保留状態とかエラー状態を useState() で処理しているコードがある。

const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, setIsPending] = useState(false);

const handleSubmit = async () => {
  setIsPending(true);
  const error = await updateName(name);
  setIsPending(false);
  if (error) {
    setError(error);
    return;
  } 
  redirect("/path");
};

これがReact19ではtransitionで非同期関数を使って、保留中のステート、エラー、フォーム、楽観的な更新を自動的に処理できるようになる。 上記のコードを useTransition() を使うと以下のようにpending状態を処理できる。

const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();

const handleSubmit = () => {
  startTransition(async () => {
    const error = await updateName(name);
    if (error) {
      setError(error);
      return;
    } 
    redirect("/path");
  })
};

非同期トランジション(async transition)はすぐにisPendingをtrueに設定し、非同期リクエストを行い、transition後にisPendingをfalseに切り替える。 フレームワーク側で制御してくれるのは何となく安心感があるかも。

New hook: useActionState

Actionsでよくあるケースを簡単にするために、useActionStateという新しいフックを追加された。

const [error, submitAction, isPending] = useActionState(
  async (previousState, newName) => {
    const error = await updateName(newName);
    if (error) {
      // Actionの結果は何でも返すことができる。
      // ここではエラーだけを返す。
      return error;
    }

    // 正常系
    return null;
  },
  null,
);
// Using <form> Actions and useActionState
function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await updateName(formData.get("name"));
      if (error) {
        return error;
      }
      redirect("/path");
      return null;
    },
    null,
  );

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </form>
  );
}

React.useActionStateは、CanaryリリースではReactDOM.useFormStateだったが、名前を変更し、useFormStateを非推奨としたとのこと。 useActionStateの詳細についてはドキュメントを参照。

React DOM: form Actions

ActionsはReact 19のreact-domの新しい<form>機能とも統合されている。 <form>, <input>, <button>要素のactionとformAction propsに関数を渡すことで、Actionを使って自動的にフォームを送信できるようになった。

<form action={actionFunction}>

<form>Actionが成功すると、Reactは制御されていないコンポーネントのフォームを自動的にリセット。<form>を手動でリセットする必要がある場合は、requestFormReset React DOM APIを呼び出すことができる。 詳細は <form><input><button>のドキュメントを参照。

React DOM: New hook: useFormStatus

デザインシステムにおいて、デザインコンポーネントを書くときに、そのコンポーネントの中にある <form>に関する情報にアクセスする必要がある。これはContextを使って行うことができるが、よくあるケースを簡単にするために、新しいhookであるuseFormStatusが追加された。

import {useFormStatus} from 'react-dom';

function DesignButton() {
  const { pending } = useFormStatus();
  return <button type="submit" disabled={pending} />
}

useFormStatusは親の<form>のステータスをContextのProvierかのように読み込んでくれるらしい! 便利そう。 詳細はドキュメントで。

New hook: useOptimistic

データミューテーションを実行するときのもう1つの一般的なUIパターンは、非同期リクエストの実行中に最終状態を楽観的に表示すること。React19ではこれを簡単にするためにuseOptimisticという新しいhookが追加されている。

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>
  );
}

useOptimisticフックは、updateNameリクエストが進行している間、直ちにoptimisticNameをレンダリングする。更新が終了するかエラーが発生すると、Reactは自動的にcurrentNameの値に切り替える。 詳細はドキュメント

New API: use

React 19では、レンダリングでリソースを読み込むための新しいAPIを導入された。 useを使ってプロミスを読み込むと、Reactはプロミスが解決するまでSuspendする。

import {use} from 'react'; // <--

function Comments({commentsPromise}) {
  // useはPromiseが解決するまでsuspendする。
  const comments = use(commentsPromise); // <--
  return comments.map(comment => <p key={comment.id}>{comment}</p>);
}

function Page({commentsPromise}) {
  // Commentsで`use`がサスペンドすると、このSuspense boundaryが表示される
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Comments commentsPromise={commentsPromise} />
    </Suspense>
  )
}

useはrenderで作成されたプロミスをサポートしていない。renderで作成されたプロミスをuseに渡そうとすると、Reactは警告を発します

ここがいまいちわかってない。

Contextも読むことができるとのこと。 ドキュメント

React Server Components

Server Components

Server Componentsは、クライアントアプリケーションやSSRサーバーとは別の環境で、バンドルする前のコンポーネントを先にレンダリングできる新しいオプション。Server Componentsは、CIサーバー上でビルド時に一度だけ実行することも、Webサーバーを使ってリクエストごとに実行することも可能。

Server Actions

クライアントコンポーネントがサーバー上で実行される非同期関数を呼び出すことを可能にする。 server actionsが"use server"ディレクティブで定義されると、フレームワークは自動的にサーバー関数への参照を作成し、その参照をクライアントコンポーネントに渡します。その関数がクライアントで呼び出されると、Reactはサーバにリクエストを送信して関数を実行し、結果を返します。 これもNextjsのapp routerで先に使ってた。便利。

よくある誤解として、Server Componentsは "use server "で示されますが、Server Components用のディレクティブはありません。use server" ディレクティブは、サーバーアクションに使用されます。

React19の改善点(気になったところ抜粋)

ref as a prop

forwardRefを使わなくても良いようになった!

function MyInput({placeholder, ref}) {
  return <input placeholder={placeholder} ref={ref} />
}

//...
<MyInput ref={ref} />

<Context> as a provider

React 19では、<Context.Provider>の代わりに<Context>をプロバイダとしてレンダリングできる。将来的に<Context.Provider>は廃止されるとのこと。

const ThemeContext = createContext('');

function App({children}) {
  return (
    <ThemeContext value="dark">
      {children}
    </ThemeContext>
  );  
}

useDeferredValue initial value

useDeferredValueにinitialValueオプションを追加。

function Search({deferredValue}) {
  // On initial render the value is ''.
  // Then a re-render is scheduled with the deferredValue.
  const value = useDeferredValue(deferredValue, '');
  
  return (
    <Results query={value} />
  );
}

ドキュメント

Support for Document Metadata

React 19では、コンポーネント内のドキュメントメタデータタグをネイティブにレンダリングするためのサポートを追加されるとのこと。react-helmetとか使わなくても良くなる!ただreact-helmetのようなライブラリが必要なケースもあるかも。

Support for stylesheets

コンポーネントごとにlinkの形式でスタイルシートを呼び出せるようになった?

function ComponentOne() {
  return (
    <Suspense fallback="loading...">
      <link rel="stylesheet" href="foo" precedence="default" />
      <link rel="stylesheet" href="bar" precedence="high" />
      <article class="foo-class bar-class">
        {...}
      </article>
    </Suspense>
  )
}

function ComponentTwo() {
  return (
    <div>
      <p>{...}</p>
      <link rel="stylesheet" href="baz" precedence="default" />  <-- will be inserted between foo & bar
    </div>
  )
}

Support for async scripts

同様にscriptのレンダリングもできるようになったぽい。

function MyComponent() {
  return (
    <div>
      <script async={true} src="..." />
      Hello World
    </div>
  )
}

function App() {
  <html>
    <body>
      <MyComponent>
      ...
      <MyComponent> // won't lead to duplicate script in the DOM
    </body>
  </html>
}
Continue reading →

More posts can be found in the archive.