如何对渲染的 React 组件进行外边距断言?

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

How can I assert against exterior margins in a rendered React component?

问题

以下是翻译好的部分:

"Detecting exterior margins should be simple enough: each time a component is rendered find its root DOM element(s), check the union of their border boxes against the union of their outer boxes, and record a diagnostic message if they differ.
(I know this is likely to be incredibly slow. It'd be activated by a runtime flag in debug builds.)"

"检测外部边距应该相对简单:每当组件被渲染时,找到其根 DOM 元素,检查它们的边框框的并集与它们的外部框的并集,如果它们不同则记录一条诊断消息。
(我知道这可能非常慢。它将通过调试构建中的运行时标志来激活。)"

"How might I run code to check this after each component's rendered elements have been reflowed? The following constraints apply:

React version 17 (currently; due for update)
We use class and occasionally function components, connected with Redux. React Hooks are forbidden, JSX/TSX is forbidden.
Extending the Component base class is forbidden, as some components already implement lifecycle methods such as componentDidMount."

"在每个组件的渲染元素被重新布局后,我该如何运行代码来检查这个问题呢?以下约束条件适用:

React 版本为 17(当前版本;将要更新)
我们使用类组件和偶尔的函数组件,与 Redux 连接。禁止使用 React Hooks,禁止使用 JSX/TSX。
禁止扩展 Component 基类,因为某些组件已经实现了像 componentDidMount 这样的生命周期方法。"

"Ideally there'd be a way to introspect the current mounted component tree on-demand, but I've been unable to find one.

Alternatively, maybe there's an existing way (plugin, etc) to identify components rendered with exterior margins?"

"理想情况下,应该有一种方法可以按需检查当前已挂载的组件树,但我尚未找到这种方法。

或者,也许有一种现有的方法(插件等)可以识别使用外部边距渲染的组件?"

英文:

One of the codebases I work with consists of several thousand React components, some of which were written before we enforced proper design standards in place around things like use of exterior margins. It's time to clean this up.

Detecting exterior margins should be simple enough: each time a component is rendered find its root DOM element(s), check the union of their border boxes against the union of their outer boxes, and record a diagnostic message if they differ.
(I know this is likely to be incredibly slow. It'd be activated by a runtime flag in debug builds.)

How might I run code to check this after each component's rendered elements have been reflowed? The following constraints apply:

  • React version 17 (currently; due for update)
  • We use class and occasionally function components, connected with Redux. React Hooks are forbidden, JSX/TSX is forbidden.
  • Extending the Component base class is forbidden, as some components already implement lifecycle methods such as componentDidMount.

Ideally there'd be a way to introspect the current mounted component tree on-demand, but I've been unable to find one.

Alternatively, maybe there's an existing way (plugin, etc) to identify components rendered with exterior margins?

答案1

得分: 0

这听起来像是可以使用测试框架完成的事情。Cypress 或者 Nightwatch 可能都可以胜任。我相信它们都会在实际浏览器中渲染组件,而且您可以在文档上运行真正的 JavaScript。

您可以编写一个测试,使用data-testid属性渲染每个组件。然后,您可以轻松地获取组件的根元素,并将其传递给一个 JavaScript 函数,该函数获取计算的边距。最棒的部分是,如果边距不正确,您可以让测试失败,这将为您提供一些强大的回归测试,并防止需要手动测试。

英文:

This sounds like something you could do with a testing framework. Cypress or Nightwatch would probably do the trick. I believe they both render components in an actual browser, and you can run real JavaScript on the document.

You could write a test that renders each component with a data-testid attribute. Then you can easily grab the root element of the component and pass it to a JavaScript function that gets the calculated margins. And the cherry on top is you can make the tests fail if the margins are wrong, which will give you some strong regression testing and prevent the need for manual testing.

答案2

得分: 0

禁止扩展组件不像我之前认为的那样绝对。实际上,我们可以通过替换构造函数中的方法,而不是像通常一样重写它们来实现这一点:

constructor(props: Readonly<{ children?: React.ReactNode }> & Readonly<P>, context?: {}) {
    super(props, context);

    // ...

    if (Debug.Margins.enabled()) {
        const oldComponentDidMount = (this as any).componentDidMount;
        (this as any).componentDidMount = () => {
            oldComponentDidMount && oldComponentDidMount.bind(this)();
            checkComponentMargins(this);
        }

        const oldComponentDidUpdate = (this as any).componentDidUpdate;
        (this as any).componentDidUpdate = (prevProps: Readonly<{ children?: React.ReactNode }> & Readonly<P>, prevState: S) => {
            oldComponentDidUpdate && oldComponentDidUpdate.bind(this)(prevProps, prevState);
            checkComponentMargins(this);
        }
    }
}

不太好,但能够工作。对其他人可能有用。

然而,我们仍然面临识别呈现组件的根元素的问题。到目前为止,我找到的最好方法是使用 findDOMNode,但它仅适用于具有单个根元素的组件(即不适用于 Fragment),并且由于我们使用严格模式,它会触发警告。

目前足够好。

英文:

The prohibition on extending Component is not as absolute as I believed. There is actually a way we can do this without breaking our codebase, by replacing methods in the constructor instead of overriding them as usual:

constructor(props: Readonly&lt;{ children?: React.ReactNode }&gt; &amp; Readonly&lt;P&gt;, context?: {}) {
    super(props, context);

    // ...

    if (Debug.Margins.enabled()) {
        const oldComponentDidMount = (this as any).componentDidMount;
        (this as any).componentDidMount = () =&gt; {
            oldComponentDidMount &amp;&amp; oldComponentDidMount.bind(this)();
            checkComponentMargins(this);
        }

        const oldComponentDidUpdate = (this as any).componentDidUpdate;
        (this as any).componentDidUpdate = (prevProps: Readonly&lt;{ children?: React.ReactNode }&gt; &amp; Readonly&lt;P&gt;, prevState: S) =&gt; {
            oldComponentDidUpdate &amp;&amp; oldComponentDidUpdate.bind(this)(prevProps, prevState);
            checkComponentMargins(this);
        }
    }
}

Not nice, but works. Might be useful for someone else.

However we still have the problem of identifying the root element(s) of the rendered component. The best I've found so far is findDOMNode but that only works for components with a single root element (ie. not Fragment) and it triggers warnings due to our use of strict mode.

Good enough for now.

huangapple
  • 本文由 发表于 2023年6月1日 15:38:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379657.html
匿名

发表评论

匿名网友

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

确定