React Guide
Learn about React-specific features, event handling, and component usage for using Flicking in your React application.
This guide is for React users. For Vue3, see the Vue3 Guide. For vanilla JavaScript, see the Quick Start guide.
Installation & Import
Package Installation
npm install @egjs/react-flicking
# or
yarn add @egjs/react-flicking
Import in Your Component
import Flicking from "@egjs/react-flicking";
import "@egjs/react-flicking/dist/flicking.css";
Make sure to use the correct package:
- ✅
@egjs/react-flicking(React) - ❌
@egjs/flicking(Vanilla JS only)
Event Handling
Event handlers in React use the on prefix with PascalCase event names.
Event Naming Pattern
Format: on + PascalCase event name
<Flicking
onReady={(e) => console.log("ready")}
onChanged={(e) => console.log("changed")}
onWillChange={(e) => console.log("willChange")}
onWillRestore={(e) => console.log("willRestore")}
onRestored={(e) => console.log("restored")}
onMoveStart={(e) => console.log("moveStart")}
onMove={(e) => console.log("move")}
onMoveEnd={(e) => console.log("moveEnd")}
onHoldStart={(e) => console.log("holdStart")}
onHoldEnd={(e) => console.log("holdEnd")}
onSelect={(e) => console.log("select")}
onNeedPanel={(e) => console.log("needPanel")}
onVisibleChange={(e) => console.log("visibleChange")}
onReachEdge={(e) => console.log("reachEdge")}>
{/* panels */}
</Flicking>
- Event name in camelCase:
changed,willChange,moveStart - Add
onprefix:onChanged,onWillChange,onMoveStart - Use PascalCase for compound words:
onVisibleChange(notonvisibleChange)
Common Event Handlers
function MyCarousel() {
// Fired AFTER panel change completes
const handleChanged = (e) => {
console.log("New panel index:", e.index);
console.log("Previous panel index:", e.prevIndex);
};
// Fired BEFORE panel change starts (cancellable)
const handleWillChange = (e) => {
console.log("Will move to:", e.index);
// Call e.stop() to prevent the change
if (e.index === 5) {
e.stop(); // Cancel navigation to panel 5
}
};
// Fired when user starts dragging
const handleMoveStart = (e) => {
console.log("User started moving");
};
return (
<Flicking
onChanged={handleChanged}
onWillChange={handleWillChange}
onMoveStart={handleMoveStart}>
{/* panels */}
</Flicking>
);
}
See Also:
ChangedEvent- Fired AFTER panel changeWillChangeEvent- Fired BEFORE panel change- All Event Interfaces
Using the Instance
Use useRef to access the Flicking instance and control the carousel programmatically.
Using useRef
import { useRef } from "react";
import Flicking from "@egjs/react-flicking";
function MyCarousel() {
const flickingRef = useRef(null);
const handlePrev = () => {
flickingRef.current?.prev();
};
const handleNext = () => {
flickingRef.current?.next();
};
const handleMoveTo = () => {
flickingRef.current?.moveTo(3);
};
return (
<div>
<Flicking ref={flickingRef}>
<div>Panel 1</div>
<div>Panel 2</div>
<div>Panel 3</div>
<div>Panel 4</div>
</Flicking>
<button onClick={handlePrev}>Previous</button>
<button onClick={handleNext}>Next</button>
<button onClick={handleMoveTo}>Move to Panel 4</button>
</div>
);
}
Use optional chaining (?.) when calling methods to avoid errors if the ref is not yet mounted:
flickingRef.current?.moveTo(2); // ✅ Safe
flickingRef.current.moveTo(2); // ❌ May error if not mounted
See Also:
Styling
In React, the className prop you pass to the <Flicking> component is applied directly to the .flicking-viewport element:
import Flicking from "@egjs/react-flicking";
import "@egjs/react-flicking/dist/flicking.css";
// className goes on the Flicking component
<Flicking className="my-carousel">
<div className="panel">Panel 1</div>
</Flicking>
/* Your custom class is applied to .flicking-viewport */
.my-carousel {
max-width: 1200px;
margin: 0 auto;
}
.panel {
width: 300px;
height: 400px;
}
You can use any styling approach (CSS files, CSS Modules, styled-components, inline styles, etc.) — the key point is that your class applies to the viewport.
For detailed information about Flicking's HTML structure, required CSS, and comprehensive styling guidelines, see HTML Structure & Styling.
React Component Panels
When using React components as panels, there are specific requirements to ensure Flicking can properly manage them.
Ref Forwarding Requirement
React components used as panels must forward refs to their root DOM element. This allows Flicking to access and manipulate the panel elements.
import { forwardRef } from "react";
import Flicking from "@egjs/react-flicking";
// ✅ Correct - Component forwards ref
const Panel = forwardRef((props, ref) => (
<div ref={ref} className="panel">
{props.children}
</div>
));
function MyCarousel() {
return (
<Flicking>
<Panel>Panel 1</Panel>
<Panel>Panel 2</Panel>
<Panel>Panel 3</Panel>
</Flicking>
);
}
// ❌ Wrong - No ref forwarding
const Panel = (props) => (
<div className="panel">
{props.children}
</div>
);
// ❌ Wrong - Multiple root elements
const Panel = forwardRef((props, ref) => (
<>
<div>Header</div>
<div ref={ref}>Content</div>
</>
));
Workarounds
If you can't modify the component to forward refs, use one of these approaches:
1. Wrap in a div (Recommended)
<Flicking>
<div><ThirdPartyComponent /></div>
<div><ThirdPartyComponent /></div>
<div><ThirdPartyComponent /></div>
</Flicking>
2. Use useFindDOMNode option
<Flicking useFindDOMNode={true}>
<ThirdPartyComponent />
<ThirdPartyComponent />
<ThirdPartyComponent />
</Flicking>
useFindDOMNode uses React's deprecated findDOMNode API and may impact performance. Wrapping in a div is the preferred solution.
React-Exclusive Options
React Flicking provides additional options not available in vanilla JS or Vue3.
HTML Tag Customization
viewportTag - Customize the viewport element's HTML tag (default: "div")
<Flicking viewportTag="section">
{/* Renders as <section class="flicking-viewport"> */}
</Flicking>
cameraTag - Customize the camera element's HTML tag (default: "div")
<Flicking cameraTag="ul">
{/* Camera renders as <ul class="flicking-camera"> */}
<li>Panel 1</li>
<li>Panel 2</li>
</Flicking>
Camera Styling
cameraClass - Add custom className to the camera element (default: "")
<Flicking cameraClass="my-camera-class">
{/* Camera will have classes: "flicking-camera my-camera-class" */}
</Flicking>
Rendering Optimization
renderOnSameKey - Control re-rendering when children have identical keys (default: false)
const [panels, setPanels] = useState([1, 2, 3]);
<Flicking renderOnSameKey={false}>
{panels.map((num) => (
<div key={num}>Panel {num}</div>
))}
</Flicking>
When false, panels with the same key won't re-render, improving performance. Set to true if you need to force re-renders.
useFindDOMNode - Enable alternative DOM access method (default: false)
<Flicking useFindDOMNode={true}>
{/* Allows components without ref forwarding */}
</Flicking>
These options are React-specific. See Flicking API for the complete reference.
Common Pitfalls
1. Wrong Import Path
// ❌ Wrong - This is vanilla JS
import Flicking from "@egjs/flicking";
// ✅ Correct - React wrapper
import Flicking from "@egjs/react-flicking";
2. Wrong Event Handler Names
// ❌ Wrong - Missing 'on' prefix
<Flicking changed={handler} />
// ❌ Wrong - Using vanilla JS event name
<Flicking on="changed" />
// ✅ Correct - onChanged with PascalCase
<Flicking onChanged={handler} />
3. Forgetting CSS Import
// ❌ Missing CSS - Panels won't display correctly
import Flicking from "@egjs/react-flicking";
// ✅ Include CSS
import Flicking from "@egjs/react-flicking";
import "@egjs/react-flicking/dist/flicking.css";
4. Accessing Methods Before Mount
function MyCarousel() {
const flickingRef = useRef(null);
// ❌ Wrong - Ref is null during render
flickingRef.current?.moveTo(2);
// ✅ Correct - Use in event handler or useEffect
useEffect(() => {
flickingRef.current?.moveTo(2);
}, []);
return <Flicking ref={flickingRef}>{/* panels */}</Flicking>;
}