非同期データ変更と処理は、モダンなウェブアプリケーションで必要な任务です。サーバーで独立した非同期関数を実行し、データストアにデータを保存、電子メールを送信、PDFをダウンロード、画像を処理などの任务を実行することがあります。

Next.jsは、Server Actionsを提供してくれます。これらは、サーバー上で実行される非同期関数であり、私たちは、サーバー上でのデータ変更などにserver actionsを使用することができます。しかし、server actionsは、サーバーおよびクライアントコンポーネントから呼び出すことができます。

Server actionsは、フォームのデータが送信されたときにアクションを実行することで、フォームの送信を処理するのに優れた方法です。この記事で、Next.jsのserver actionsで追加の引数を処理する実用的な使用例について見ていきましょう。

Next.jsのServer Actionsをデザインパターンとプロジェクト構築について学ぶことに興味を持つという場合、私はあなたに対するクラッシュコースを作成しました。ここから

また、この記事はビデオチュータリアルとしてここで見ることができます。

目次

  1. 追加の引数を渡す必要がある理由

  2. サーバーアクションを持つフォーム

  3. 追加の引数を渡す方法

  4. 隠しフィールドについては?

  5. リソース

追加の引数を渡す必要性とは?

フォームの送信時にサーバーのアクションを実行する場合、サーバーのアクションは自動的にフォームのデータを取得する。たとえば以下のフォームを見てください。

<form className="p-4 flex" action={updateUser}>
  <Input className="w-1/2 mx-2" type="text" name="name" />
  <Button type="submit">Update User Name</Button>
</form>

ここで、フォームが送信されると updateUser というサーバーアクションが実行されます。updateUser 関数は送信されたフォームデータを引数として受け取り、これを使ってフォームのフィールド値を抽出することができます。

以下のコードスニペットで、updateUser 関数は formData を引数として受け取り、そこから name フィールドの値を抽出することができます。

"use server"

export async function updateUser(formData) {
  const name = formData.get('name');
  console.log(name);
}

このパターンはほとんどの基本的な使用事例をカバーしていますが、プログラム的に追加の引数をサーバーのアクションに渡す必要がある場合があります。これらの引数はフォームやフォームデータ、ユーザーの入力データの一部ではありません。これらはプログラム的に渡される値であり、サーバーのアクションに追加の計算を行うために使用されます。

これについて理解するために、以下のサーバーアクションのコードスニペットをご確認ください。これは以前に見たものと同じサーバーアクションですが、通常のformData引数とともにuserId追加引数を渡しています。

"use server"

export async function updateUser(userId, formData) {
  const name = formData.get('name');
  console.log(userId);
  console.log(name);
}

userIdの値はアプリの内部のものです。この値をフォーム送信の一部として用户提供する必要はないです。代わりに、追加の計算を行うためにプログラム的にサーバーアクションに渡す必要がある場合があります。

正しいのは私たちが話している用途です。私たちがなぜ必要だと理解したので、どのように実現するかを理解しましょう。まずは、表单とそれに対応する機能のあるサーバーアクションを作成しましょう。

サーバーアクションによる表单

Next.jsアプリケーションのappディレクトリー下面にactionsディレクトリーを作成します。そして、actionsフォルダーに以下のコードのuser.jsファイルを作成します。

"use server"

export async function updateUser(formData) {
  const name = formData.get('name');
  console.log(name);

  // 名前を何でもして、DBに保存し、請求書を作成してください!
}

これがNext.jsでサーバー機能を作成する方法です。ファイルの先頭に”use server”ディレクティブを追加して、Next.jsにこれが特別なファイルで、1つ以上の非同期関数をサーバー上で実行することを示してください。

次に、サーバーのアクション(非同期関数)updateUserformDataを引数として使用しています。関数定義の内部で、nameの値を抽出し、コンソールに出力します。

次に、このサーバーのアクションをフォームに結合しましょう。これを行うために、プロジェクトのルートフォルダー下にcomponentsというフォルダーを作成し、次のコードを持つuser-form.jsxというファイルを作成します。

import { Input } from "./ui/input"
import { Button } from "./ui/button"

import { updateUser } from "@/app/actions/user"

const UserForm = () => {
  return(
    <form className="p-4 flex" action={updateUser}>
      <Input className="w-1/2 mx-2" type="text" name="name" />
      <Button type="submit">Update User Name</Button>
    </form>
  )
}

export default UserForm;

これは、単純なReactコンポーネントで、フォームがあります。このフォームには、nameという名前の入力テキストフィールドと、フォームを送信するための送信按钮が含まれています。このフォームにはaction属性があり、updateUserというサーバーアクションを値として含まれています。今度、フォームがnameの値で送信されると、先程述べたように、サーバーアクションはフォームデータの一部として取得します。

試すために、Next.jsのルートとページを作成し、UserFormコンポーネントを使用できるようにしましょう。appディレクトリー下にextra-argsというフォルダーを作成し、app/extra-argsディレクトリー下に次のコードを持つpage.jsというファイルを作成します。

import UserForm from "@/components/user-form";

const ExtraArgsDemo = () => {
  return (
    <UserForm />
  )
}

export default ExtraArgsDemo;

これは、単純なReactコンポーネントです。ここにUserFormコンポーネントをインポートし、JSX内で使用しています。今、ローカルサーバーを実行し、このルートlocalhost:3000/extra-argsにアクセスしてください。テキストフィールドとボタンのあるフォームを表示されるはずです。

テキストフィールドにテキストを入力し、ボタンをクリックしてください。

現在、打ち込んだテキストがサーバーコンソールに印刷されていることがわかります。なぜサーバーコンソールにですか?ブラウザーコンソールにはなぜですか?これはサーバー上でのアクションがクライアントサイドのブラウザー上ではなく、サーバー上で実行されるからです。

これにより、次のようなデータフローを Establish しました。

Page => Form => Server Action

ページにはフォームがあり、フォームは送信時にサーバーアクションを実行します。サーバーアクションはサーバーコンソールにフォームデータを印刷します。

これから、これらの部材を強化し、サーバーアクションに追加の引数を渡すことです。

追加の引数を渡す方法

PageからUserFormコンポーネントにuserIdを渡す。このuserIdの値を Pretend して、このuserIdをプログラム的に私たちのフォームやサーバーアクションに渡すことをします。

import UserForm from "@/components/user-form";

const ExtraArgsDemo = () => {
  return (
    <UserForm userId={"1234"} />
  )
}

export default ExtraArgsDemo;

UserFormコンポーネントでuserIdのプロパティを受け取ります。今、このuserIdupdateUserサーバーアクションに渡すために特別なことをしなければなりません。

JavaScriptにはbind()と呼ばれる魔法的な方法があり、これは部分的に適用された関数(Partially Applied Function)を作成することを助けます。この部分的に適用された関数を使用して、他の関数の既定の引数から関数を作成することができます。

私たちの場合、updateUser 関数にはすでに formData という引数があります。ここで、bind() メソッドを使って追加の引数として userId を渡し、新しい関数を作成できます。

const updatedUserWithId = updateUser.bind(null, userId);

bind() メソッドの最初の引数は、関数をバインドするコンテキストです。このコンテキストは、this キーワードの値との関連付けを処理します。私たちの場合、それを変更しないので null のままにしておくことができます。その後、新しい引数 userId を渡しました。bind() メソッドはサーバーとクライアントの両方のコンポーネントで機能することを知っておくと良いでしょう。

ここで変更された UserForm コンポーネント(user-form.jsx ファイル)を示します。フォームアクションの値は、新しい関数 updatedUserWithId に変更されていることに注意してください。

import { Input } from "./ui/input"
import { Button } from "./ui/button"

import { updateUser } from "@/app/actions/user"

const UserForm = ({userId}) => {
  const updatedUserWithId = updateUser.bind(null, userId);

  return(
    <form className="p-4 flex" action={updatedUserWithId}>
      <Input className="w-1/2 mx-2" type="text" name="name" />
      <Button type="submit">Update User Name</Button>
    </form>
  )
}

export default UserForm;

これで、サーバーアクションは引数として userId の値を受け取ります。それをコンソールに出力してみましょう。

"use server"

export async function updateUser(userId, formData) {
  const name = formData.get('name');
  console.log(userId);
  console.log(name);

  // ユーザーIDと名前で何かを行い、DBに保存し、
  // 請求書を作成するなど!
}

名前の値を入力してフォームを送信すると:

userId と名前の値が両方ともサーバーコンソールに記録されているのがわかります。素晴らしいですね!フォームデータから一つの値を記録し、もう一つは内部的にサーバーアクションに渡されました。

このようにして、フォームデータと一緒に追加の引数をサーバーアクションに渡す方法を学びました。

隠しフィールドはどうでしょうか?

HTMLは、ユーザーからの入力を受け付けずにクライアントのデータをサーバーに送るための隐しタイプのフォームフィールドをサポートしています。つまり、私たちはuserIdの値を次のように隐しフィールドを使用して送信することができます。

ですので、なぜ私たちはbind()メソッドを使ってこれらの操作を行ったのでしょうか。というのも、安全性の疑念に基づいています。隐しフィールドを使用してデータを渡す場合、値はレンダrized HTMLの一部になり、エンコードされないため、プログラム的に处理する方がよいです。

リソース

今回の記事はここで終わります。この記事を読んでおり、新しいことを学びましたか?そうであれば、コンテンツが有益か否か知りたいです。私は、この記事で使用した全てのソースコードが GitHubにあります。

さらに、私とコミュニケートすることができます:

次の記事で再会します。そのまま、自分自身に注意を払い、学び続けてください。