无法访问下一服务器操作中的值|Next.js 13.4

gojuced7  于 2023-06-22  发布在  其他
关注(0)|答案(1)|浏览(73)

我很好奇我们如何能够访问Next.js 13的alpha版本的服务器操作返回值。Here's the documentation从下一个团队参考。
假设我有以下示例服务器操作来执行输入验证:

async function validation(formData: FormData) { // needs "formData" or else errors
    'use server';
    
    // Get the data from the submitted form
    const data = formData?.get("str");
    
    // Sanitize the data and put it into a "str" const
    const str = JSON.stringify(data)
        .replace(/['"]+/g, '')
    
    // Self explanatory
    if (!str) {
        return { error: "String is Required" }
    } 

    else if (!(/^[a-zA-Z0-9]{8}$/).test(str)) {
        return { error : "Invalid String Format" }
    }

    // Using next/navigation, redirect to another dynamic page
    // if the data is validated
    
    await redirect(`/scan-code=${str}`)
    return null;
    }

这个动作被挂接到一个简单的形式上:

<form action={validation}>
    <label>
        {error && error}
    </label>
    <input 
        placeholder="Enter String Here"
        required 
        name="str"
    />
    <button type="submit">
        Submit
    </button>
</form>

在Remix中,这是一个非常简单的使用动作和useFetcher()钩子的例子,动作看起来基本上是一样的,除了在组件本身中,您会使用类似
const fetcher = useFetcher()
然后
const error = fetcher.data?.error
并处理UI中的错误

<label style={{ color: error ? 'red' : 'black' }}>
{error && error}
</label>

然而,我并不能检索错误值并根据它们是否存在来呈现它们,实际上我只是返回一个错误或重定向到正确的页面,所以UI中没有错误的反馈。
当尝试首先使用动作时,也会出现类型错误,async函数的promises与元素上的动作 prop 的预期类型不匹配,显然是字符串。
TS2322: Type '(formData: FormData) => Promise<{ error: string; } | null>' is not assignable to type 'string'
我很好奇我在这里做错了什么,以及Remix的useFetcher()useActionData()钩子的替代品将用于Next的服务器操作,因为我觉得在上下文,本地存储或DB中持久化错误将是不必要的步骤。
任何和所有的帮助将不胜感激。谢谢你!

pcrecxhr

pcrecxhr1#

基于这个GitHub discussion上的非常简洁的响应,您只能使用客户端呈现的表单来完成此操作。在我的例子中,我有一个服务器呈现的页面。该页定义内联服务器操作,然后将该操作传递给客户端呈现的窗体。客户端呈现的表单用另一个async函数 Package 服务器操作,然后将新的 Package 函数传递给form['action']程序。

// app/whatever/new/client-rendered-form.tsx

"use client";

import { useState } from "react";

export default ClientRenderedForm({
  serverAction
}: {
  serverAction: (data: FormData) => Promise<unknown>
}) {
  const [error, setError] = useState<unknown>();

  return (
    <form
      action={async (data: FormData) => {
        try {
          await serverAction(data);
        } catch (e: unknown) {
          console.error(e);

          setError(e);
        }
      }}
    >
      <label>
        <span>Name</span>
        <input name="name" />
      </label>

      <button type="submit">pull the lever!</button>
    </form>
  );
}
// app/whatever/new/page.tsx

import { redirect } from "next/navigation";

import ClientRenderedForm from "./client-rendered-form";

export default WhateverNewPage() {
  const serverAction = async (data: FormData) => {
    "use server";

    // i don't know why the 'use server' directive is required,
    // but it is. this file is already executed on the server
    //
    // this function runs on the server. you may process the data
    // however you'd like
    //
    // if this function throws, the client wrapper will catch
    //
    // when you are finished, you likely need to execute a
    // `redirect()`. i don't know if the `return` keyword
    // is required

    return redirect("/somewhere/else");
  };

  return (
    <div className="fancy-layout">
      <ClientRenderedForm {...{ serverAction }} />
    </div>
  );
}

我希望这对你有帮助!对于这个新的范例来说,现在还处于早期阶段,所以文档还没有填写好。

相关问题