Open franciszekjob opened 3 years ago
@Fiiranek thanks for the kind words!
Thats a good idea. It shouldn't be too hard to build a wrapper for React.
Any progress on this?
Here's a stripped down version of how I integrated this with React:
'use client'
import {useState, useRef, useEffect} from "react";
// @ts-ignore
import {Wheel} from 'spin-wheel/dist/spin-wheel-esm'
interface WheelItem {
label: string
}
interface SpinWheel {
spinToItem: (
itemIndex: number,
duration?: number,
spinToCenter?: boolean,
numberOfRevolutions?: number,
easingFunction?: null | ((t: number) => number)
) => void
}
const randomizeNumber = (number: number) => Math.floor(Math.random() * number);
const Home = () => {
const wheelItems: WheelItem[] = [
{
label: 'a'
},
{
label: 'b'
},
{
label: 'c'
}
]
const container = useRef(null)
const [mounted, setMounted] = useState(false)
const [wheel, setWheel] = useState<SpinWheel>()
useEffect(() => {
if (!container) return
console.log('render wheel')
setWheel(new Wheel(container.current, {
items: wheelItems,
}))
setMounted(true)
}, [])
return <div style={{display: 'flex', flexDirection: 'column', height: '100%'}}>
<div style={{flexDirection: 'row', justifyContent: 'space-between', flex: 0, margin: '12px'}}>
<button
onClick={() => {
wheel!.spinToItem(randomizeNumber(wheelItems.length), 4000, true, 5)
}}
disabled={!mounted}
>Randomize!
</button>
</div>
<div id="wheel" ref={container} style={{
width: '100vw',
height: '100vw',
overflow: 'hidden'
}}></div>
</div>
}
export default Home
If its useful to anyone else, I implemented it as a hook:
In order for it to work with typescript, you will need to grab the typescript types from this convo: https://github.com/CrazyTim/spin-wheel/issues/23
import { Wheel, WheelProps } from "spin-wheel";
import { useEffect, useMemo, useRef, useState } from "react";
interface UseWheelResult {
wheel: Wheel | null;
wheelComponent: JSX.Element;
}
export function useWheel({
initialProps: _initialProps,
}: {
initialProps: WheelProps;
}): UseWheelResult {
const wheelRef = useRef(null);
const [wheel, setWheel] = useState<Wheel | null>(null);
const [initialProps] = useState(_initialProps);
useEffect(() => {
if (!wheelRef || wheel) return;
setWheel(new Wheel(wheelRef.current as any, initialProps));
}, [initialProps, wheelRef, wheel]);
const wheelComponent = useMemo(() => {
return (
<div
ref={wheelRef}
style={{
width: "100%",
height: "100%",
}}
/>
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return {
wheel,
wheelComponent,
};
}
Usage:
import { FC } from "react";
import { useWheel } from "./use-wheel";
import { Wheel } from "spin-wheel";
const randomizeNumber = (number: number) => Math.floor(Math.random() * number);
const wheelItems: Wheel["items"] = [
{
label: "a",
},
{
label: "b",
},
{
label: "c",
},
];
const ElementWheel: FC = () => {
const { wheel, wheelComponent } = useWheel({
initialProps: { items: wheelItems },
});
return (
<div className="h-full w-full">
<div className="w-full h-full">
<button
className="absolute top-0 left-0 z-10"
onClick={() => {
wheel!.spinToItem(
randomizeNumber(wheelItems.length),
4000,
true,
5
);
}}
>
Spin!
</button>
</div>
<div className="w-full h-full absolute top-0 left-0">
{wheelComponent}
</div>
</div>
);
};
export default ElementWheel;
If its useful to anyone else, I implemented it as a hook:
In order for it to work with typescript, you will need to grab the typescript types from this convo: #23
import { Wheel, WheelProps } from "spin-wheel"; import { useEffect, useMemo, useRef, useState } from "react"; interface UseWheelResult { wheel: Wheel | null; wheelComponent: JSX.Element; } export function useWheel({ initialProps: _initialProps, }: { initialProps: WheelProps; }): UseWheelResult { const wheelRef = useRef(null); const [wheel, setWheel] = useState<Wheel | null>(null); const [initialProps] = useState(_initialProps); useEffect(() => { if (!wheelRef || wheel) return; setWheel(new Wheel(wheelRef.current as any, initialProps)); }, [initialProps, wheelRef, wheel]); const wheelComponent = useMemo(() => { return ( <div ref={wheelRef} style={{ width: "100%", height: "100%", }} /> ); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return { wheel, wheelComponent, }; }
Usage:
import { FC } from "react"; import { useWheel } from "./use-wheel"; import { Wheel } from "spin-wheel"; const randomizeNumber = (number: number) => Math.floor(Math.random() * number); const wheelItems: Wheel["items"] = [ { label: "a", }, { label: "b", }, { label: "c", }, ]; const ElementWheel: FC = () => { const { wheel, wheelComponent } = useWheel({ initialProps: { items: wheelItems }, }); return ( <div className="h-full w-full"> <div className="w-full h-full"> <button className="absolute top-0 left-0 z-10" onClick={() => { wheel!.spinToItem( randomizeNumber(wheelItems.length), 4000, true, 5 ); }} > Spin! </button> </div> <div className="w-full h-full absolute top-0 left-0"> {wheelComponent} </div> </div> ); }; export default ElementWheel;
It's working great but i have a problem. I'm using React Strict mode and that is causing rendering wheel twice. How can fix that?
It's working great but i have a problem. I'm using React Strict mode and that is causing rendering wheel twice. How can fix that?
React strict is suppose to make the component run twice in development mode, it's there to help you discover side-effects that might not show on initial render.
It's working great but i have a problem. I'm using React Strict mode and that is causing rendering wheel twice. How can fix that?
React strict is suppose to make the component run twice in development mode, it's there to help you discover side-effects that might not show on initial render.
Of course I know that. I don't want to disable Strict mode but I need to prevent that from that happening. I don't want 2 spin wheels 😅
Hey, did you consider creating an equivalent in React? I think it would be veery useful for many people in the community, because the number of options that you provide here, is ridiculously huge (in a good way)! Really appreciate you job!