简体   繁体   English

如何修复“警告:useLayoutEffect 在服务器上什么都不做”?

[英]How to fix the "Warning: useLayoutEffect does nothing on the server"?

Heres the full error:这是完整的错误:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format.警告:useLayoutEffect 在服务器上什么都不做,因为它的效果不能被编码成服务器渲染器的 output 格式。 This will lead to a mismatch between the initial, non-hydrated UI and the intended UI.这将导致初始的非水合 UI 和预期的 UI 不匹配。 To avoid this, useLayoutEffect should only be used in components that render exclusively on the client为避免这种情况,useLayoutEffect 应仅在仅在客户端上呈现的组件中使用

 in ForwardRef(ButtonBase) in WithStyles(ForwardRef(ButtonBase)) in ForwardRef(Button) in WithStyles(ForwardRef(Button)) in form in div

I get it every time I run my test.我每次运行测试时都会得到它。 Heres my test这是我的测试

/* eslint-disable quotes */
import React from "react"
import { shallow, configure } from "enzyme"
import LoginForm from "../src/components/LoginForm"
import Button from "@material-ui/core/Button"
import Adapter from "enzyme-adapter-react-16"
import { render, fireEvent, cleanup } from "@testing-library/react"

configure({ adapter: new Adapter() })

describe("<LoginForm />", () => {
  let wrapper
  let usernameInput
  let passwordInput
  let signInButton

  // Create initial props that get passed into the component
  const initialProps = {
    location: {
      state: {
        from: {
          pathname: "/",
        },
      },
    },
  }

  // Unit testing
  describe("Unit tests", () => {
    // what to do before each test
    beforeEach(() => {
      // Render the login form component, pass in props. (Shallow method renders the component without its children, good for unit tests.)
      wrapper = shallow(<LoginForm {...initialProps} />)
      usernameInput = wrapper.find("#username")
      passwordInput = wrapper.find("#password")
      signInButton = wrapper.find(Button)
    })

    // what to do after each test
    afterEach(() => {
      jest.clearAllMocks()
    })

    // UI Integrity test
    it("should match the snapshot", () => {
      // snapshots are text references of the html of the rendered component.
      expect(wrapper.html()).toMatchSnapshot()
    })

    it("should have a username inputs", () => {
      expect(usernameInput.length).toEqual(1)
    })

    it("should have the expected props on the username field", () => {
      expect(usernameInput.props()).toEqual({
        id: "username",
        name: "username",
        value: "",
        type: "username",
        onChange: expect.any(Function),
        required: true,
      })
    })

    it("should have a password field", () => {
      expect(passwordInput.length).toEqual(1)
    })

    it("should have the expected props on the password field", () => {
      expect(passwordInput.props()).toEqual({
        id: "password",
        name: "password",
        value: "",
        type: "password",
        onChange: expect.any(Function),
        required: true,
      })
    })

    it("should have a submit button", () => {
      expect(signInButton.length).toEqual(1)
    })

    it("should have the expected props on the button", () => {
      expect(signInButton.props()).toEqual({
        type: "button",
        variant: "contained",
        style: expect.objectContaining({
          marginTop: "10px",
        }),
        onClick: expect.any(Function),
        children: "Sign In",
      })
    })
  })

  // Integrations Testing
  describe("Integrations tests", () => {
    beforeEach(() => {
      // Render the login form component, pass in props. (render method renders the component with its children, good for integrations tests, uses react-test-library.)
      const { getByLabelText, getByText } = render(
        <LoginForm {...initialProps} />
      )
      usernameInput = getByLabelText(/Username/i)
      passwordInput = getByLabelText(/Password/i)
      signInButton = getByText("Sign In")
    })

    afterEach(cleanup)

    it("Username text change in onChange event", () => {
      expect(usernameInput.value).toBe("")

      fireEvent.change(usernameInput, { target: { value: "James" } })

      expect(usernameInput.value).toBe("James")
    })

    it("Password text change in onChange event", () => {
      expect(passwordInput.value).toBe("")

      fireEvent.change(passwordInput, { target: { value: "mypassword" } })

      expect(passwordInput.value).toBe("mypassword")
    })

    it("Test button submit", () => {
      const mockLogin = jest.fn()

      const button = shallow(<Button onClick={mockLogin} />)

      button.simulate("click")

      expect(mockLogin.mock.calls.length).toEqual(1)
    })
  })
})

I believe it has something to do with the material-ui component.我相信它与 material-ui 组件有关。 I've looked into it, theres a similar question on here that says the issue has to do with a dependency that my project does not have.我已经调查过了, 这里有一个类似的问题,说这个问题与我的项目没有的依赖关系有关。 So I think it has to do with the material-ui component using useEffectLayout and the testing env doesnt like that for some reason.所以我认为这与使用useEffectLayout的 material-ui 组件有关,并且由于某种原因,测试环境不喜欢这样。 Im running my test with yarn and jest yarn test to run the test suite.我用 yarn 和 jest yarn test运行我的测试来运行测试套件。

adding添加

import React from "react" 
React.useLayoutEffect = React.useEffect 

to my frontend/src/setupTests.js test file is a way to suppress the jest warning.到我的前端/src/setupTests.js 测试文件是一种抑制开玩笑警告的方法。 Ultimately, this looks to be an issue with Material-UI components having issues with Jest.最终,这似乎是 Material-UI 组件与 Jest 存在问题的问题。

A bit cleaner solution might be to use jest mock like so:更清洁的解决方案可能是像这样使用 jest mock:

jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useLayoutEffect: jest.requireActual('react').useEffect,
}));

you should check if the useLayoutEffect can be used this way:你应该检查 useLayoutEffect 是否可以这样使用:

import React, {useEffect, useLayoutEffect} from 'react';

const canUseDOM = typeof window !== 'undefined';
const useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;

then instead of the useLayoutEffect use a useIsomorphicLayoutEffect然后代替useLayoutEffect使用useIsomorphicLayoutEffect

You can fix this by adding the following if statement to the beginning of your startup file (eg index.js):您可以通过将以下 if 语句添加到启动文件(例如 index.js)的开头来解决此问题:

if (typeof document === 'undefined') {
  React.useLayoutEffect = React.useEffect;
}

This will ensure that the SSR uses React.useEffect instead of React.useLayoutEffect because document is undefined on the server-side.这将确保 SSR 使用React.useEffect而不是React.useLayoutEffect因为document在服务器端未定义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在使用 Material UI 和 reactDOMServer 时修复“警告:useLayoutEffect 在服务器上什么都不做”? - How to fix "Warning: useLayoutEffect does nothing on the server" while using Material UI and reactDOMServer? NextJs / Framer Motion:使用 useViewportScroll 时我收到此警告:警告:useLayoutEffect 在服务器上不执行任何操作, - NextJs / Framer Motion: When using useViewportScroll I got this warning: Warning: useLayoutEffect does nothing on the server, usePreventScroll 在 Nextjs 中导致 useLayoutEffect 警告 - usePreventScroll causes useLayoutEffect warning in Nextjs 如何修复 React 无法识别 `basePath` 警告? - How to fix the React does not recognize the `basePath` warning? 如何修复此警告:DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE - How does fix this Warning: DEP_WEBPACK_DEV_SERVER_ON_AFTER_SETUP_MIDDLEWARE 当 React JS 分页组件在点击时什么都不做时如何修复? - How to fix when React JS Pagination component does Nothing on Click? 如何在控制台中修复“来自服务器的额外属性:样式”警告 - How to fix 'Extra attributes from the server: style' warning in console 如何在反应 useLayoutEffect 中去抖动? - How to debounce inside a react useLayoutEffect? 如何修复反应警告 - How to fix React Warning React 如何在浏览器有机会绘制之前正确测量 useLayoutEffect 钩子中的 DOM 元素? - How does React measure DOM Elements in useLayoutEffect hook correctly before browser gets a chance to paint?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM