英文:
Why is it not object destructuring when calling useActionData() in react router dom?
问题
当我调用useActionData()时,我没有得到任何对象的解构。当我在控制台上打印时,我得到了name: 'isakGo'。代码如下:
export async function action({ request }) {
  const formData = await request.formData();
  const name = { name: formData.get("name") };
  return { name };
}
export default function FormTest() {
  const { name } = useActionData(); // 这里发生了错误
  // 其他代码
}
我们正在使用createBrowserRouter()创建路由,并使用RouterBrowser进行服务。
const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <ErrorPage />,
    children: [
      {
        path: "/FormTest",
        element: <FormTest />,
        action: formTestAction,
      },
    ],
  },
]);
发生了以下错误。
> 无法解构(0, react_router_dom__WEBPACK_IMPORTED_MODULE_1__.useActionData)(...)的属性'name',因为它未定义。
如果将代码更改为不进行对象解构的代码,它将正常工作。
export async function action({ request }) {
  const formData = await request.formData();
  const name = { name: formData.get("name") };
  return name;
}
export default function FormTest() {
  const name = useActionData(); 
  // 其他代码
}
当我在react-router-dom中写像loader()这样的东西时,即const { name } = useLoaderData();,它可以正常工作。action()没有破坏对象。我漏掉了什么?
我正在使用create-react-app和react-router-dom@6.11.2版本。
编辑
我们发现可能直接与错误相关的其他因素。
- 当加载
FormTest()时,会调用useActionData(),因此空的name变量为空。 - 由于某种原因,当我将结果打印到控制台时,它被调用了4次。
 
英文:
When I call useActionData(), I don't get any object destruction. When I print to the console, I get name: 'isakGo'. The code looks like this
export async function action({request}) {
  const formData = await request.formData();
  const name = { name: formData.get("name") }
  return { name };
}
export default function FormTest() {
  const { name } = useActionData(); // error has occured here
  // other codes
}
We're creating a router with createBrowserRouter() and serving it with RouterBrowser.
const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <ErrorPage />,
    children: [
      {
        path: "/FormTest",
        element: <FormTest />,
        action: formTestAction,
      }
    ]
  },
])
The following error occurs.
> Cannot destructure property 'name' of '(0 , react_router_dom__WEBPACK_IMPORTED_MODULE_1__.useActionData)(...)' as it is undefined.
If you change your code to one that doesn't do object destruction, it will work cleanly.
export async function action({request}) {
  const formData = await request.formData();
  const name = { name: formData.get("name") }
  return name;
}
export default function FormTest() {
  const name = useActionData(); 
  // other codes
}
When I write something like loader() in react router dom, i.e. const { name } = useLoaderData();, it works fine. action() is not destroying the object. what am I missing?
I'm using the create-react-app and the react-router-dom@6.11.2 version.
Edit
We found additional factors that may be directly related to the error.
- useActionData() is called when FormTest() is loaded, so the empty name variable is empty.
 - for some reason, it is called 4 times when I print the results to the console.
 
答案1
得分: 1
文档
> 此钩子提供了前一次导航操作结果的返回值,如果没有提交,则返回 undefined。
function SomeComponent() {
  let actionData = useActionData();
  // ...
}
> 此钩子的最常见用例是表单验证错误。如果表单不正确,您可以返回错误并让用户重试:
代码示例
import {
  useActionData,
  Form,
  redirect,
} from "react-router-dom";
export default function SignUp() {
  const errors = useActionData();
  return (
    <Form method="post">
      <p>
        <input type="text" name="email" />
        {errors?.email && <span>{errors.email}</span>}
      </p>
      <p>
        <input type="text" name="password" />
        {errors?.password && <span>{errors.password}</span>}
      </p>
      <p>
        <button type="submit">Sign up</button>
      </p>
    </Form>
  );
}
export async function action({ request }) {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const errors = {};
  // 验证字段
  if (typeof email !== "string" || !email.includes("@")) {
    errors.email =
      "那不像是一个电子邮件地址";
  }
  if (typeof password !== "string" || password.length < 6) {
    errors.password = "密码必须大于6个字符";
  }
  // 如果有错误则返回数据
  if (Object.keys(errors).length) {
    return errors;
  }
  // 否则创建用户并重定向
  await createUser(email, password);
  return redirect("/dashboard");
}
英文:
Documentation
> This hook provides the returned value from the previous navigation's action result, or undefined if there was no submission.
function SomeComponent() {
  let actionData = useActionData();
  // ...
}
> The most common use-case for this hook is form validation errors. If the form isn't right, you can return the errors and let the user try again:
Code Example
import {
  useActionData,
  Form,
  redirect,
} from "react-router-dom";
export default function SignUp() {
  const errors = useActionData();
  return (
    <Form method="post">
      <p>
        <input type="text" name="email" />
        {errors?.email && <span>{errors.email}</span>}
      </p>
      <p>
        <input type="text" name="password" />
        {errors?.password && <span>{errors.password}</span>}
      </p>
      <p>
        <button type="submit">Sign up</button>
      </p>
    </Form>
  );
}
export async function action({ request }) {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const errors = {};
  // validate the fields
  if (typeof email !== "string" || !email.includes("@")) {
    errors.email =
      "That doesn't look like an email address";
  }
  if (typeof password !== "string" || password.length < 6) {
    errors.password = "Password must be > 6 characters";
  }
  // return data if we have errors
  if (Object.keys(errors).length) {
    return errors;
  }
  // otherwise create the user and redirect
  await createUser(email, password);
  return redirect("/dashboard");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论