使用 React 生成 Flicking 轮播导致 getComputedStyle 错误

Generating a Flicking carousel with React leads to the getComputedStyle error

这个问题是关于 egjs-flicking 图书馆的,但也许问题更普遍。

让我们考虑两个仅在 render() 方法上有所不同的组件示例。首先我提供整个组件。

import React from 'react';

import Flicking, { MoveEvent, FlickingError } from "@egjs/react-flicking";

class Credits extends React.Component {
    constructor(props) {
        super(props);
        this.readtime = 1000;
        this.maxElements = 4;
        this.actionReady = this.actionReady.bind(this);
        this.actionReset = this.actionReset.bind(this);
        this.actionMove = this.actionMove.bind(this);
        this.processFlicking = this.processFlicking.bind(this);
    }

    async actionReady(e) {
        const status = e.currentTarget.getStatus();
        setTimeout(() => {
            e.currentTarget.moveTo(status.position.panel + 1);
        }, this.readTime);
    }

    async actionReset(e, delay) {
        setTimeout(() => {
            e.currentTarget.moveTo(0);
        }, delay);
    }

    async actionMove(e) {
        const status = e.currentTarget.getStatus();
        setTimeout(() => {
            e.currentTarget.moveTo(status.position.panel + 1);
        }, this.readTime);
    }

    async processFlicking(e) {
        const status = e.currentTarget.getStatus();
        const remaining = status.panels.length - status.position.panel;
        if (remaining == this.maxElements) {
            this.actionReset(e, this.readtime*this.maxElements);
        } else {
            this.actionMove(e);
        }
    }

    getMStyle() {
        return {
            'overflow': 'hidden'
        };
    }

    render() {
        // this is where the examples differ
    }
}

静态案例

现在第一种情况是Flicking容器的子容器是预定义的。

render() {
        const PanelComponent = this.props.panelComponent;
        return (
            <Flicking
              style={this.getMStyle()}
              circular={false}
              align={"prev"}
              horizontal={false}
              onReady={this.actionReady}
              onMoveEnd={this.processFlicking}
            >
              <div>hello</div><div>sup</div><div>how are u</div><div>cze</div><div>konnichiwa</div><div>salam</div><div>namaste</div>
            </Flicking>
        );
    }

它给出了以下呈现的 HTML

<div class="flicking-camera">
  <div>hello</div>
  <div>sup</div>
  <div>how are u</div>
  <div>cze</div>
  <div>konnichiwa</div>
  <div>salam</div>
  <div>namaste</div>
</div>

动态案例

这里是动态生成的

render() {
        const PanelComponent = this.props.panelComponent;
        return (
            <Flicking
              style={this.getMStyle()}
              circular={false}
              align={"prev"}
              horizontal={false}
              onReady={this.actionReady}
              onMoveEnd={this.processFlicking}
            >
              { this.props.panels.map((data, index) =>
                  ( <PanelComponent key={index} data={data.content} /> )) }
            </Flicking>
        );
    }

给出以下呈现的 HTML(与之前相同)

<div class="flicking-camera">
  <div>hello</div>
  <div>sup</div>
  <div>how are u</div>
  <div>cze</div>
  <div>konnichiwa</div>
  <div>salam</div>
  <div>namaste</div>
</div>

它正在使用的 PanelComponent

class EntryElement extends React.Component {
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>{ this.props.data }</div>
        )
    }
}

生成每个面板。

问题

静态案例完美运行,动态案例给出以下错误

Uncaught (in promise) TypeError: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
    at getStyle (utils.ts:259:1)
    at Panel.__proto.resize (Panel.ts:323:1)
    at Renderer.ts:163:1
    at Array.forEach (<anonymous>)
    at ReactRenderer.__proto.updatePanelSize (Renderer.ts:163:1)
    at Flicking.<anonymous> (Flicking.ts:1227:1)
    at step (index.ts:1:1)
    at Object.next (index.ts:1:1)
    at fulfilled (index.ts:1:1)

我真的很困惑为什么因为结果 HTML 是相同的...有什么想法吗?

好的,我真的找到了。感谢this GitHub discussion and here是我的相关评论。

来自 https://naver.github.io/egjs-flicking/docs/quick-start 我检查了部分 Bypassing ref forwarding 并将 useFindDOMNode={true} 添加到我的 Flicking。

这是能够在 Flicking 中动态放置子组件的完整工作源代码

class Credits extends React.Component {
    constructor(props) {
        super(props);
        this.readtime = 1000;
        this.maxElements = 4;
        this.actionReady = this.actionReady.bind(this);
        this.actionReset = this.actionReset.bind(this);
        this.actionMove = this.actionMove.bind(this);
        this.processFlicking = this.processFlicking.bind(this);
        this.createPanel = this.createPanel.bind(this);
    }

    async actionReady(e) {
        const status = e.currentTarget.getStatus();
        setTimeout(() => {
            e.currentTarget.moveTo(status.position.panel + 1);
        }, this.readTime);
    }

    async actionReset(e, delay) {
        setTimeout(() => {
            e.currentTarget.moveTo(0);
        }, delay);
    }

    async actionMove(e) {
        const status = e.currentTarget.getStatus();
        setTimeout(() => {
            e.currentTarget.moveTo(status.position.panel + 1);
        }, this.readTime);
    }

    async processFlicking(e) {
        const status = e.currentTarget.getStatus();
        const remaining = status.panels.length - status.position.panel;
        if (remaining == this.maxElements) {
            this.actionReset(e, this.readtime*this.maxElements);
        } else {
            this.actionMove(e);
        }
    }

    getMStyle() {
        return {
            'overflow': 'hidden'
        };
    }

    createPanel(panel, index) {
        const PanelComponent = this.props.panelComponent;
        return <PanelComponent data={panel.content} key={index} />;
    }

    createPanels(panels) {
        return panels.map(this.createPanel);
    }

    render() {
        const panels = this.props.panels;
        return (
            <Flicking
              useFindDOMNode={true}
              style={this.getMStyle()}
              circular={false}
              align={"prev"}
              horizontal={false}
              onReady={this.actionReady}
              onMoveEnd={this.processFlicking}
            >
              { this.createPanels(panels) }
            </Flicking>
        );
    }
}