Next.js Discord

Discord Forum

Invalid hook call error when trying to call function from other file

Unanswered
Brown bear posted this in #help-forum
Open in Discord
Brown bearOP
Want to create button in another component but onclick to make it call the addRect within the FabricCanvas.tsx file but getting invalid hook call error. How would I be able to make the button in a separate component yet still be able to call this function?
Toolbar.tsx
import addRect from "./FabricCanvas";
import canvas from "./FabricCanvas";

export default function Toolbar() {
  return (
    <div className="fixed top-10 left-0 bottom-0 w-1/20 bg-gray-200 p-4">
      <Card>
        <div className="flex flex-col auto">
          <Button onClick={addRect}>Rectangle</Button>
        </div>
      </Card>
    </div>
  );
}

FabricCanvas.tsx
export const FabricCanvas = () => {
  const [canvas, setCanvas] = useState<fabric.Canvas>();

  useEffect(() => {
    const c = new fabric.Canvas("canvas", {
      height: window.innerHeight,
      width: window.innerWidth,
      backgroundColor: "white",
    });

    // settings for all canvas in the app
    fabric.Object.prototype.transparentCorners = false;
    fabric.Object.prototype.cornerColor = "#2BEBC8";
    fabric.Object.prototype.cornerStyle = "rect";
    fabric.Object.prototype.cornerStrokeColor = "#2BEBC8";
    fabric.Object.prototype.cornerSize = 6;

    setCanvas(c);

    return () => {
      c.dispose();
    };
  }, []);

  const addRect = (canvas?: fabric.Canvas) => {
    if (!canvas) return;
    const rectWidth = 200;
    const rectHeight = 280;

    const rect = new fabric.Rect({
      left: 600,
      top: 200,
      height: rectHeight,
      width: rectWidth,
      stroke: "#2BEBC8",
      fill: "transparent",
      strokeUniform: true,
    } as CustomRectOptions);
...

1 Reply

hoist up addRect to a component (or context) that contains both FabricCanvas and Toolbar

make some state that you keep in this component that represents the rectangles in their simplest form eg

const [rectangles, setRectangles] = useState([])

function addRect() {
  const newRectangle = { width: 200, height: 280 }
  setRectangles(rectangles => [...rectangles, newRectangle])
}


pass down rectangles to the FabricCanvas

then you can use this state to add the "real" rectangles to fabric

useEffect(() => {
    fabric.clear() // clear the canvas, idk how to actually do this in fabric
    rectangles.forEach(rectangle => {
        // use the width and height from the rectangle to add it to fabric
        const rect = new fabric.Rect({.... etc
    })
}, [rectangles])


does that make sense?