I m really sorry if this question is answered a thousand times before, I m really new to React, and don't know how to describe what I want to say in correct words to search for it.
I have a canvas component (A simple HTML canvas and I am using fabric.js on top of it) and a sidebar component (Which contains quite a few buttons such as a button to change line thickness, line color etc). Now what I want is when I click on the button in the sidebar (say, change line color button), it will call a function in canvas component or anywhere else, that sets the color property to be used for canvas drawing.
IMPORTANT: After a bit of googling what I found is that React encourages self-containment, all logic for a component should be inside it. But I am trying to make a whiteboard app. There are different toolbox, menu, sidebar components - all of which affect my canvas. I was writing the code for it in plain HTML, CSS, JavaScript. But I soon realized that my code was getting too difficult to read and modify. This is where I searched for something that lets me break my HTML code into pieces for easy management - such as one HTML code for toolbox, another one for the sidebar etc. And React and similar frameworks appeared. React does the job I originally searched for - breaking my code into components. But I am not getting how to do the following in React:
```var lineColor = #000000; const canvas = document.getElementById("canvas-id"); const lineColorButton = document.getElementById("line-color-button-id"); lineColorButton.addEventListened("click", () => {lineColor = #ff0000;})```
ANOTHER IMPORTANT NOTE: I do not want to use React as it is a bit too overwhelming for me right now. I wanted to stick with simple HTML. I just wanted a solution to break my HTML code into pieces for easy management. PLEASE any type of advice would be really appreciated.
CodePudding user response:
The parent component can contain the methods you want, and pass the function to the child component.
The following it just typed out by hand, so may contain typos...
// In the parent component:
const onEraseToolClicked = (aParam) => {
console.log(`Erase tool with ${aParam} was clicked`)
}
// optionally memoize the function so it won't cause re-render unless a variable it uses changes
const onEraseToolClickedMemo = useCallback(onEraseToolClicked, [])
return (
<>
<Toolbar onEraseToolClicked={onEraseToolClickedMemo} />
</>
)
//IN THE Toolbar.js File
function Toolbar({ onEraseToolClickedMemo }) {
return (
<>
<button type='button' onClick={onEraseToolClickedMemo}>click me</button>
<button type='button' onClick={()=>onEraseToolClickedMemo('hello')} >no click me</button>
</>
)
}
EDIT: You may also look into using react's context. You can put the toolbar state and methods to set/change it's state into the context. Then wrap your command pallet and the canvas with the context. This will make it easier to deal with a lot of state and toolbar items.
CodePudding user response:
I see that you already have an accepted answer, but if you wanted to stick with vanilla js you could set up a class to manage the canvas. The class could expose whatever functionality you need and your toolbar controls could just invoke those methods.
Here's a very rudimentary proof of concept.
class Canvas {
constructor (context) {
this.ctx = context;
this.fillColorIndex = 0;
this.paint();
}
onFillChange () {
// cycle to the next color
this.ctx.fillStyle = colors[this.fillColorIndex % colors.length];
// redraw
this.paint();
}
paint () {
// fill a rect so we have something to look at
this.ctx.fillRect(50,50,100,100);
}
}
// get references to the canvas and button dom elements
const elem = document.querySelector('canvas');
const button = document.querySelector('button');
// list of fill styles to cycle through
const colors = ['red', 'green', 'blue', 'tomato', 'bisque',];
// instantiate the class with the canvas element's 2d context.
const c = new Canvas(elem.getContext('2d'));
// set up the button to invoke a method on the instance
button.addEventListener('click', () => c.onFillChange())
/* just basic layout stuff. not relevant to the functionality */
.demo {
display: flex;
flex-direction: column;
gap: 10px;
width: 200px;
margin: 1rem auto;
}
canvas {
border: 1px dotted grey;
}
<div >
<button>Next Color</button>
<canvas width="200" height="200"></canvas>
</div>