Next.js 中的所有输入都导致完全重新渲染

All inputs in Next.js are causing a full re-render

我现在正在使用版本 12.1.5 开发 Next.js 应用程序,我 运行 遇到了一个非常疯狂的错误。每个输入组件都会导致每次击键时完全重新渲染,从而导致失去对输入的关注。这适用于 inputtextarea,甚至 @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 允许我通过传入元素类型来创建任何元素的弹性框 - divbuttonnav 等,我在我的输入组件中使用该组件。删除我的 createElement 函数并用简单的 div 替换它解决了问题,所以现在我只需要重构 Flex 组件以仍然允许任何元素类型。

综上所述,Flex 组件在其子项更改时会导致完整渲染。去更正。