Home > Enterprise >  What is the recommended way to call a function in another component when a button is clicked in Reac
What is the recommended way to call a function in another component when a button is clicked in Reac

Time:02-26

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>

  • Related