Next.js 中的所有输入都导致完全重新渲染
All inputs in Next.js are causing a full re-render
我现在正在使用版本 12.1.5
开发 Next.js 应用程序,我 运行 遇到了一个非常疯狂的错误。每个输入组件都会导致每次击键时完全重新渲染,从而导致失去对输入的关注。这适用于 input
、textarea
,甚至 @monaco-editor/react
包。我在 Formik
表单中遇到了同样的问题,并且奇怪地能够通过切换到 react-hook-form
来解决问题。但是,我仍然在所有接受击键的组件上看到它。
我试过将组件的值状态向上移动到树中,尝试将状态放在组件本地,但我完全没有运气。这是我的 input
组件的样子:
Input.tsx
import { forwardRef, InputHTMLAttributes, ReactNode, Ref } from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import css from 'classnames';
import { Flex } from 'containers/flex/Flex';
import s from './Input.module.scss';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
showLabel?: boolean;
icon?: ReactNode;
}
export const Input = forwardRef(
(
{ showLabel, name, className, label, icon, ...rest }: InputProps,
ref: Ref<HTMLInputElement>
) => {
return (
<Flex column className={css(s.input, className)}>
{showLabel && (
<LabelPrimitive.Label htmlFor={name} className={s.input__label}>
{label}
</LabelPrimitive.Label>
)}
<Flex alignCenter className={s.input__icon}>
{icon && icon}
</Flex>
<input
ref={ref}
name={name}
{...rest}
className={css(s.input__field, icon && s.hasIcon)}
/>
</Flex>
);
}
);
Input.displayName = 'Input';
如果我实现这样的值:
TestComponent.tsx
import { useState } from 'react';
import { Input } from 'elements/input/Input';
export const TestComponent = () => {
const [value, setValue] = useState('');
return <Input value={value} onChange={setValue}/>;
};
每当我尝试打字时,我都会失去注意力。同样,这发生在我在 react-hook-form
之外尝试过的每个输入实现上,包括 @monaco-editor/react
包。
这也是我的 package.json 以防其他软件包出现问题。
package.json
{
"name": "app",
"version": "0.6.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest",
"test:watch": "jest --watch",
"vercel:build": "prisma generate && prisma migrate deploy && next build",
"dev:connect": "pscale connect veroskills development --port 3309",
"shadow:connect": "pscale connect veroskills shadow --port 3309",
"slicemachine": "start-slicemachine",
"prepare": "husky install"
},
"dependencies": {
"@hookform/resolvers": "^2.8.8",
"@monaco-editor/react": "^4.4.4",
"@next-auth/prisma-adapter": "^1.0.3",
"@prisma/client": "^3.13.0",
"@prismicio/client": "^6.4.2",
"@prismicio/helpers": "^2.2.1",
"@prismicio/next": "^0.1.2",
"@prismicio/react": "^2.2.0",
"@prismicio/slice-simulator-react": "^0.2.1",
"@radix-ui/react-alert-dialog": "^0.1.7",
"@radix-ui/react-checkbox": "^0.1.5",
"@radix-ui/react-dialog": "^0.1.7",
"@radix-ui/react-dropdown-menu": "^0.1.6",
"@radix-ui/react-icons": "^1.1.0",
"@radix-ui/react-label": "^0.1.5",
"@radix-ui/react-progress": "^0.1.4",
"@radix-ui/react-scroll-area": "^0.1.4",
"@radix-ui/react-select": "^0.1.1",
"@radix-ui/react-separator": "^0.1.4",
"@radix-ui/react-switch": "^0.1.5",
"@radix-ui/react-tabs": "^0.1.5",
"@radix-ui/react-toast": "^0.1.1",
"@radix-ui/react-toolbar": "^0.1.5",
"@radix-ui/react-tooltip": "^0.1.7",
"bcryptjs": "^2.4.3",
"classnames": "^2.3.1",
"dayjs": "^1.11.0",
"next": "^12.1.5",
"next-auth": "^4.3.1",
"next-compose-plugins": "^2.2.1",
"next-images": "^1.8.4",
"next-react-svg": "^1.1.3",
"node-mocks-http": "^1.11.0",
"path": "^0.12.7",
"plyr-react": "^3.2.1",
"prismic-reactjs": "^1.3.4",
"react": "^18.0.0",
"react-code-blocks": "^0.0.9-0",
"react-dom": "^18.0.0",
"react-gravatar": "^2.6.3",
"react-hook-form": "^7.30.0",
"react-loading-skeleton": "^3.1.0",
"react-select": "^5.2.2",
"react-table": "^7.7.0",
"react-use-keypress": "^1.3.1",
"sass": "^1.50.0",
"swr": "^1.3.0",
"use-monaco": "^0.0.40",
"yup": "^0.32.11"
},
"devDependencies": {
"@prismicio/types": "^0.1.27",
"@types/bcryptjs": "^2.4.2",
"@types/jest": "^27.4.1",
"@types/node": "17.0.21",
"@types/react": "18.0.1",
"@types/react-dom": "^18.0.0",
"@types/react-gravatar": "^2.6.10",
"@types/react-table": "^7.7.10",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"eslint": "8.12.0",
"eslint-config-next": "12.1.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.0",
"jest": "^27.5.1",
"lint-staged": "^12.3.7",
"prettier": "^2.6.2",
"prisma": "^3.13.0",
"slice-machine-ui": "^0.3.7",
"ts-jest": "^27.1.4",
"turbo": "^1.2.4",
"typescript": "^4.6.3"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"yarn eslint --fix",
"yarn prettier --write"
]
}
}
我在这里完全不知所措;有人知道问题出在哪里吗?
我已经通过一些广泛的调试解决了我的问题。我有一个可重用的 Flex
组件,它利用 createElement
允许我通过传入元素类型来创建任何元素的弹性框 - div
、button
、nav
等,我在我的输入组件中使用该组件。删除我的 createElement
函数并用简单的 div
替换它解决了问题,所以现在我只需要重构 Flex
组件以仍然允许任何元素类型。
综上所述,Flex
组件在其子项更改时会导致完整渲染。去更正。
我现在正在使用版本 12.1.5
开发 Next.js 应用程序,我 运行 遇到了一个非常疯狂的错误。每个输入组件都会导致每次击键时完全重新渲染,从而导致失去对输入的关注。这适用于 input
、textarea
,甚至 @monaco-editor/react
包。我在 Formik
表单中遇到了同样的问题,并且奇怪地能够通过切换到 react-hook-form
来解决问题。但是,我仍然在所有接受击键的组件上看到它。
我试过将组件的值状态向上移动到树中,尝试将状态放在组件本地,但我完全没有运气。这是我的 input
组件的样子:
Input.tsx
import { forwardRef, InputHTMLAttributes, ReactNode, Ref } from 'react';
import * as LabelPrimitive from '@radix-ui/react-label';
import css from 'classnames';
import { Flex } from 'containers/flex/Flex';
import s from './Input.module.scss';
interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
label?: string;
showLabel?: boolean;
icon?: ReactNode;
}
export const Input = forwardRef(
(
{ showLabel, name, className, label, icon, ...rest }: InputProps,
ref: Ref<HTMLInputElement>
) => {
return (
<Flex column className={css(s.input, className)}>
{showLabel && (
<LabelPrimitive.Label htmlFor={name} className={s.input__label}>
{label}
</LabelPrimitive.Label>
)}
<Flex alignCenter className={s.input__icon}>
{icon && icon}
</Flex>
<input
ref={ref}
name={name}
{...rest}
className={css(s.input__field, icon && s.hasIcon)}
/>
</Flex>
);
}
);
Input.displayName = 'Input';
如果我实现这样的值:
TestComponent.tsx
import { useState } from 'react';
import { Input } from 'elements/input/Input';
export const TestComponent = () => {
const [value, setValue] = useState('');
return <Input value={value} onChange={setValue}/>;
};
每当我尝试打字时,我都会失去注意力。同样,这发生在我在 react-hook-form
之外尝试过的每个输入实现上,包括 @monaco-editor/react
包。
这也是我的 package.json 以防其他软件包出现问题。
package.json
{
"name": "app",
"version": "0.6.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest",
"test:watch": "jest --watch",
"vercel:build": "prisma generate && prisma migrate deploy && next build",
"dev:connect": "pscale connect veroskills development --port 3309",
"shadow:connect": "pscale connect veroskills shadow --port 3309",
"slicemachine": "start-slicemachine",
"prepare": "husky install"
},
"dependencies": {
"@hookform/resolvers": "^2.8.8",
"@monaco-editor/react": "^4.4.4",
"@next-auth/prisma-adapter": "^1.0.3",
"@prisma/client": "^3.13.0",
"@prismicio/client": "^6.4.2",
"@prismicio/helpers": "^2.2.1",
"@prismicio/next": "^0.1.2",
"@prismicio/react": "^2.2.0",
"@prismicio/slice-simulator-react": "^0.2.1",
"@radix-ui/react-alert-dialog": "^0.1.7",
"@radix-ui/react-checkbox": "^0.1.5",
"@radix-ui/react-dialog": "^0.1.7",
"@radix-ui/react-dropdown-menu": "^0.1.6",
"@radix-ui/react-icons": "^1.1.0",
"@radix-ui/react-label": "^0.1.5",
"@radix-ui/react-progress": "^0.1.4",
"@radix-ui/react-scroll-area": "^0.1.4",
"@radix-ui/react-select": "^0.1.1",
"@radix-ui/react-separator": "^0.1.4",
"@radix-ui/react-switch": "^0.1.5",
"@radix-ui/react-tabs": "^0.1.5",
"@radix-ui/react-toast": "^0.1.1",
"@radix-ui/react-toolbar": "^0.1.5",
"@radix-ui/react-tooltip": "^0.1.7",
"bcryptjs": "^2.4.3",
"classnames": "^2.3.1",
"dayjs": "^1.11.0",
"next": "^12.1.5",
"next-auth": "^4.3.1",
"next-compose-plugins": "^2.2.1",
"next-images": "^1.8.4",
"next-react-svg": "^1.1.3",
"node-mocks-http": "^1.11.0",
"path": "^0.12.7",
"plyr-react": "^3.2.1",
"prismic-reactjs": "^1.3.4",
"react": "^18.0.0",
"react-code-blocks": "^0.0.9-0",
"react-dom": "^18.0.0",
"react-gravatar": "^2.6.3",
"react-hook-form": "^7.30.0",
"react-loading-skeleton": "^3.1.0",
"react-select": "^5.2.2",
"react-table": "^7.7.0",
"react-use-keypress": "^1.3.1",
"sass": "^1.50.0",
"swr": "^1.3.0",
"use-monaco": "^0.0.40",
"yup": "^0.32.11"
},
"devDependencies": {
"@prismicio/types": "^0.1.27",
"@types/bcryptjs": "^2.4.2",
"@types/jest": "^27.4.1",
"@types/node": "17.0.21",
"@types/react": "18.0.1",
"@types/react-dom": "^18.0.0",
"@types/react-gravatar": "^2.6.10",
"@types/react-table": "^7.7.10",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"eslint": "8.12.0",
"eslint-config-next": "12.1.4",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.0",
"jest": "^27.5.1",
"lint-staged": "^12.3.7",
"prettier": "^2.6.2",
"prisma": "^3.13.0",
"slice-machine-ui": "^0.3.7",
"ts-jest": "^27.1.4",
"turbo": "^1.2.4",
"typescript": "^4.6.3"
},
"lint-staged": {
"**/*.{js,jsx,ts,tsx}": [
"yarn eslint --fix",
"yarn prettier --write"
]
}
}
我在这里完全不知所措;有人知道问题出在哪里吗?
我已经通过一些广泛的调试解决了我的问题。我有一个可重用的 Flex
组件,它利用 createElement
允许我通过传入元素类型来创建任何元素的弹性框 - div
、button
、nav
等,我在我的输入组件中使用该组件。删除我的 createElement
函数并用简单的 div
替换它解决了问题,所以现在我只需要重构 Flex
组件以仍然允许任何元素类型。
综上所述,Flex
组件在其子项更改时会导致完整渲染。去更正。