Bobby Tables
Bobby Tables

Reputation: 163

Dispatching and listeing for events in different components - reactjs

I am trying to create a custom event in one component and add an event listener in another component. The component that is listening for the event contains a function that I want to execute on the event. Below are what I have in the two components, I just feel like I'm going about this in the wrong way...

Component #1

toggleWidget() {
   const event = new CustomEvent('sliderClicked', {
     bubbles: true,
   });
   const sliderToggle = document.getElementById('input');
   sliderToggle.dispatchEvent(event);

   this.setState({
     checked: !this.state.checked,
   });
}
  /* and then in my render... */

 render() {
   const displaySlider = this.state.isSliderDisplayed ? (
     <div className="slider-container" >
    <label className="switch" htmlFor="input">
      <input type="checkbox" checked={this.state.checked} onChange={this.toggleWidget} id="input" />
      <span className="slider round" />
    </label>
    <p className="batch-slider-title"> Batch Widget </p>
  </div>) : null;`

Component Two

window.addEventListener('sliderClicked', this.refreshLayout);`

Any ideas as to what I may be doing wrong?

Upvotes: 1

Views: 1385

Answers (3)

Jeremy Schrader
Jeremy Schrader

Reputation: 396

Refs are generally considered something to avoid in React as they couple components together. see the documentation here: https://facebook.github.io/react/docs/refs-and-the-dom.html

Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy. See the Lifting State Up guide for examples of this.

Try using a global state container like redux and when you "toggleWidget" in one component, set a property in your redux store. Listen to that property by setting it as a prop in your second component(the one that you want to respond to a change/toggle). On change of that property your component will have the "componentWillReceiveProps" lifecycle method called and you can then have your "responding" component take whatever action you like.

Upvotes: 0

jonahe
jonahe

Reputation: 5000

In React it's pretty common to pass down callbacks from parent to child.

const Child = ({handleClick}) => (
  <div onClick={ handleClick } >Click me!</div>
);

const Parent = () => {
  const childClickHandler = event => {
    // do stuff
    alert('My child is calling?');
  }

  return (
    <Child handleClick={ childClickHandler }/>
  );
};

Maybe that could work for you? You can try the code here. (JSFiddle)

Upvotes: 0

Dekel
Dekel

Reputation: 62556

Basically it should work, but in react - if you rendered an element in a component you can use the ref to access it:

<input
    type="checkbox"
    checked={this.state.checked}
    onChange={this.toggleWidget}
    id="input"
    ref={(c) => this.input = c}
/>

And your toggleWidget function should be something like this:

toggleWidget() {
    ...
    this.input.dispatchEvent(event);
    ...
}

Upvotes: 3

Related Questions