如果在一个.tsx文件中使用了”use client”,那么ssr是如何发生的?

huangapple go评论153阅读模式
英文:

How does ssr is happening if I have used "use client" in a tsx file?

问题

我刚刚开始使用nextJS 13.4.12,目前正在将一个项目从React迁移到nextJS。在处理登录页面时,我发现nextJS不允许在服务器端组件上使用react-hook-form@hookform/resolvers/yup。为了让它们工作,你需要在组件的顶部添加use client。我也这样做了。

但令我惊讶的是,当我查看网络请求时,我仍然可以看到基本的HTML代码,包括输入框、按钮和其他一些标签。这里是如何进行服务器端渲染的?

PS:我看过很多文章、教程、片段和文档。它们直接使用hook-form和yupresolver,而没有实际指定use client。尽管它们大多使用的是13.0.5版本。

以下是我的代码:

  1. // React Imports
  2. 'use client';
  3. import Link from 'next/link';
  4. import { useForm, Controller } from 'react-hook-form';
  5. import './login.css';
  6. import Image from 'next/image';
  7. // Resolvers & Schema
  8. import { yupResolver } from '@hookform/resolvers/yup';
  9. import { signupSchema } from '@/schema/auth';
  10. // Others
  11. import { headerNameLogo } from '@/EntryFile/imagePath';
  12. import Head from 'next/head';
  13. export default function Login() {
  14. const {
  15. handleSubmit,
  16. control,
  17. setError,
  18. clearErrors,
  19. formState: { errors, isValid },
  20. } = useForm({
  21. mode: 'onChange',
  22. resolver: yupResolver(signupSchema),
  23. });
  24. return (
  25. <>
  26. <Head>
  27. <title>Login - HRXpress</title>
  28. <meta name="description" content="Login page" />
  29. <script src="./togglePassword.ts"></script>
  30. </Head>
  31. <div className="account-content">
  32. <div className="container">
  33. {/* Account Logo */}
  34. <div className="account-logo" style={{ marginTop: 70 }}>
  35. <Link href="/app/main/dashboard">
  36. <Image
  37. style={{ width: 'auto', mixBlendMode: 'darken' }}
  38. src={headerNameLogo}
  39. alt="HRXpress"
  40. />
  41. </Link>
  42. </div>
  43. {/* /Account Logo */}
  44. <div className="account-box">
  45. <div className="account-wrapper">
  46. <h3 className="account-title">Login</h3>
  47. <p className="account-subtitle">Access to our dashboard</p>
  48. {/* Account Form */}
  49. <div>
  50. <form
  51. onSubmit={(e) => {
  52. e.preventDefault();
  53. }}
  54. >
  55. <div className="form-group">
  56. <label>Email Address</label>
  57. <Controller
  58. name="email"
  59. control={control}
  60. render={({ field: { value, onChange } }) => (
  61. <input
  62. className={`form-control ${
  63. errors?.email ? 'error-input' : ''
  64. }`}
  65. type="text"
  66. value={value}
  67. onChange={onChange}
  68. autoComplete="false"
  69. />
  70. )}
  71. defaultValue="admin@dreamguys.co.in"
  72. />
  73. <small>{errors?.email?.message}</small>
  74. </div>
  75. <div className="form-group">
  76. <div className="row">
  77. <div className="col">
  78. <label>Password</label>
  79. </div>
  80. <div className="col-auto">
  81. <Link className="text-muted" href="/forgotpassword">
  82. Forgot password?
  83. </Link>
  84. </div>
  85. </div>
  86. <Controller
  87. name="password"
  88. control={control}
  89. render={({ field: { value, onChange } }) => (
  90. <div className="pass-group">
  91. <input
  92. type="password"
  93. className={`form-control ${
  94. errors?.password ? 'error-input' : ''
  95. }`}
  96. value={value}
  97. onChange={onChange}
  98. autoComplete="false"
  99. />
  100. <span
  101. id="togglePassword"
  102. className="fa toggle-password fa-eye"
  103. />
  104. </div>
  105. )}
  106. defaultValue="123456"
  107. />
  108. <small>{errors?.password?.message}</small>
  109. </div>
  110. <div className="form-group text-center">
  111. <button
  112. disabled={!isValid}
  113. className="btn btn-primary account-btn"
  114. type="submit"
  115. >
  116. Login
  117. </button>
  118. </div>
  119. </form>
  120. <div className="account-footer">
  121. <p>
  122. Don't have an account yet?{' '}
  123. <Link href="/register">Register</Link>
  124. </p>
  125. </div>
  126. </div>
  127. </div>
  128. </div>
  129. </div>
  130. </div>
  131. </>
  132. );
  133. }

希望对你有所帮助!

英文:

I have just started working on nextJS 13.4.12 and currently shifting a project from react to nextJS. While working on the login page I found that nextJS does not allow to use react-hook-form or @hookform/resolvers/yup on server-side components. For them to work you need to add use client at the very top of the component. And I also did that.

But to my surprise when I see the network request I can still see the basic HTML code consisting of input, buttons, and some other tags as well.
How does ssr happening here?

PS: I have seen a ton of articles, tutorials, snippets, and docs. They were directly using hook-form, yupresolver without actually specifying use client. Although they were mostly using 13.0.5.
如果在一个.tsx文件中使用了”use client”,那么ssr是如何发生的?

Here is my code

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

  1. // React Imports
  2. &#39;use client&#39;;
  3. import Link from &#39;next/link&#39;;
  4. import { useForm, Controller } from &#39;react-hook-form&#39;;
  5. import &#39;./login.css&#39;;
  6. import Image from &#39;next/image&#39;;
  7. // Resolvers &amp; Schema
  8. import { yupResolver } from &#39;@hookform/resolvers/yup&#39;;
  9. import { signupSchema } from &#39;@/schema/auth&#39;;
  10. // Others
  11. import { headerNameLogo } from &#39;@/EntryFile/imagePath&#39;;
  12. import Head from &#39;next/head&#39;;
  13. export default function Login() {
  14. const {
  15. handleSubmit,
  16. control,
  17. setError,
  18. clearErrors,
  19. formState: { errors, isValid },
  20. } = useForm({
  21. mode: &#39;onChange&#39;,
  22. resolver: yupResolver(signupSchema),
  23. });
  24. return (
  25. &lt;&gt;
  26. &lt;Head&gt;
  27. &lt;title&gt;Login - HRXpress&lt;/title&gt;
  28. &lt;meta name=&quot;description&quot; content=&quot;Login page&quot; /&gt;
  29. &lt;script src=&quot;./togglePassword.ts&quot;&gt;&lt;/script&gt;
  30. &lt;/Head&gt;
  31. &lt;div className=&quot;account-content&quot;&gt;
  32. &lt;div className=&quot;container&quot;&gt;
  33. {/* Account Logo */}
  34. &lt;div className=&quot;account-logo&quot; style={{ marginTop: 70 }}&gt;
  35. &lt;Link href=&quot;/app/main/dashboard&quot;&gt;
  36. &lt;Image
  37. style={{ width: &#39;auto&#39;, mixBlendMode: &#39;darken&#39; }}
  38. src={headerNameLogo}
  39. alt=&quot;HRXpress&quot;
  40. /&gt;
  41. &lt;/Link&gt;
  42. &lt;/div&gt;
  43. {/* /Account Logo */}
  44. &lt;div className=&quot;account-box&quot;&gt;
  45. &lt;div className=&quot;account-wrapper&quot;&gt;
  46. &lt;h3 className=&quot;account-title&quot;&gt;Login&lt;/h3&gt;
  47. &lt;p className=&quot;account-subtitle&quot;&gt;Access to our dashboard&lt;/p&gt;
  48. {/* Account Form */}
  49. &lt;div&gt;
  50. &lt;form
  51. onSubmit={(e) =&gt; {
  52. e.preventDefault();
  53. }}
  54. &gt;
  55. &lt;div className=&quot;form-group&quot;&gt;
  56. &lt;label&gt;Email Address&lt;/label&gt;
  57. &lt;Controller
  58. name=&quot;email&quot;
  59. control={control}
  60. render={({ field: { value, onChange } }) =&gt; (
  61. &lt;input
  62. className={`form-control ${
  63. errors?.email ? &#39;error-input&#39; : &#39;&#39;
  64. }`}
  65. type=&quot;text&quot;
  66. value={value}
  67. onChange={onChange}
  68. autoComplete=&quot;false&quot;
  69. /&gt;
  70. )}
  71. defaultValue=&quot;admin@dreamguys.co.in&quot;
  72. /&gt;
  73. &lt;small&gt;{errors?.email?.message}&lt;/small&gt;
  74. &lt;/div&gt;
  75. &lt;div className=&quot;form-group&quot;&gt;
  76. &lt;div className=&quot;row&quot;&gt;
  77. &lt;div className=&quot;col&quot;&gt;
  78. &lt;label&gt;Password&lt;/label&gt;
  79. &lt;/div&gt;
  80. &lt;div className=&quot;col-auto&quot;&gt;
  81. &lt;Link className=&quot;text-muted&quot; href=&quot;/forgotpassword&quot;&gt;
  82. Forgot password?
  83. &lt;/Link&gt;
  84. &lt;/div&gt;
  85. &lt;/div&gt;
  86. &lt;Controller
  87. name=&quot;password&quot;
  88. control={control}
  89. render={({ field: { value, onChange } }) =&gt; (
  90. &lt;div className=&quot;pass-group&quot;&gt;
  91. &lt;input
  92. type=&quot;password&quot;
  93. className={`form-control ${
  94. errors?.password ? &#39;error-input&#39; : &#39;&#39;
  95. }`}
  96. value={value}
  97. onChange={onChange}
  98. autoComplete=&quot;false&quot;
  99. /&gt;
  100. &lt;span
  101. id=&quot;togglePassword&quot;
  102. className=&quot;fa toggle-password fa-eye&quot;
  103. /&gt;
  104. &lt;/div&gt;
  105. )}
  106. defaultValue=&quot;123456&quot;
  107. /&gt;
  108. &lt;small&gt;{errors?.password?.message}&lt;/small&gt;
  109. &lt;/div&gt;
  110. &lt;div className=&quot;form-group text-center&quot;&gt;
  111. &lt;button
  112. disabled={!isValid}
  113. className=&quot;btn btn-primary account-btn&quot;
  114. type=&quot;submit&quot;
  115. &gt;
  116. Login
  117. &lt;/button&gt;
  118. &lt;/div&gt;
  119. &lt;/form&gt;
  120. &lt;div className=&quot;account-footer&quot;&gt;
  121. &lt;p&gt;
  122. Don&#39;t have an account yet?{&#39; &#39;}
  123. &lt;Link href=&quot;/register&quot;&gt;Register&lt;/Link&gt;
  124. &lt;/p&gt;
  125. &lt;/div&gt;
  126. &lt;/div&gt;
  127. &lt;/div&gt;
  128. &lt;/div&gt;
  129. &lt;/div&gt;
  130. &lt;/div&gt;
  131. &lt;/&gt;
  132. );
  133. }

<!-- end snippet -->

答案1

得分: 1

这是因为在最新版本的Next.js中,每个组件都会首先在服务器端进行渲染,而不管你使用了什么指令。请参考这里了解更多信息。

英文:

It is because in latest version of nextJS each component is firstly rendered on the server side, irrespective of directive you've used. Please refer here for more.

huangapple
  • 本文由 发表于 2023年8月9日 17:09:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76866210.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定