This question is about egjs-flicking library but perhaps problem is more general.
Let us consider two examples of components that will differ only by their render()
method. First I provide the whole component.
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 } }
Static case
Now the first case is the children of the Flicking
container are pre-defined.
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> ); }
which gives the following rendered 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>
Dynamic case
Here they are generated dynamically
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> ); }
giving the following rendered HTML (identical to previous)
<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>
for PanelComponent it was using
class EntryElement extends React.Component { constructor(props) { super(props); } render() { return ( <div>{ this.props.data }</div> ) } }
to generate each of the panels.
Problem
The static case works perfectly, the dynamic case gives the following error
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)
and I am really puzzled why because resulting HTML is identical… Any ideas?
Advertisement
Answer
Ok I actually found it. All thanks to this GitHub discussion and here is my relevant comment.
From https://naver.github.io/egjs-flicking/docs/quick-start I checked section Bypassing ref forwarding
and added useFindDOMNode={true}
to my Flicking.
Here is the complete working source that is able to dynamically put children components in 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> ); } }