Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Selectors with React is ok?

I know mixing jQuery and ReactJS is not advisable, because ReactJS is not aware of any modifications to the DOM made by jQuery. But what if you only use jQuery for querying the DOM and finding nodes easily and conveniently, while leaving all the DOM editing to ReactJS. Other than jQuery being a big library, are there any other downsides to this?

An example use case is setting up event listeners whenever a dropdown menu component mounts that check to see if the user clicks anywhere off the menu, so that the menu can close. The jQuery .parents() method is a very convenient way to check if the the click target is a child of the menu container element. Is there an easy way to do this in ReactJS or with vanilla JavaScript?

Here is a code sample of this example:

handleClick = e => {
  const element = $(e.target)
  if( !( element.parents('.menu').length || element.hasClass('menu'))) {
    this.setState({ menuOpen: false })
  }
}

componentWillUpdate (nextProps, nextState) {
  if(nextState.menuOpen && !this.state.menuOpen) {
    document.addEventListener('click', this.handleClick, false)
  } else if (!nextState.menuOpen && this.state.menuOpen) {
    document.removeEventListener('click', this.handleClick, false)
  }
}
like image 651
Leo Fabrikant Avatar asked Nov 08 '22 15:11

Leo Fabrikant


1 Answers

Yes, I would say there are disadvantages to using jQuery in React.

The VDOM diffing algorithm will get confused

This is one that you mentioned. Yes, it will be fine if you use only read-only attributes, but unless you're targeting older browsers something like document.querySelector would be lighter weight.

Every depedency you're bringing in, especially as one as large as library, should be meticulously vetted. See the website obesity epedemic for details.

In addition, the idea of "I will only use it for reading and let React do the rest" will add a significant layer of confusion to your code, as we'll see in the next example.

You abandon the patterns of React

In my opinion, the bigger issue is abandoning the patterns of React. To describe React in one sentence, I would say:

React is a component-based library used to generate HTML, CSS, and JavaScript functionality derived from state inputs.

Let's say I have a simple UserProfile component. This component will have some data about the user, including a switch to receive push notifications or not:

// Please note this is simplified pseudo-code, and will likely not work
class UserProfile extends Component {
  state = {
    name: 'Bob',
    profilePic: 'someurl.com/profile-pic',
    isReceivingNotifications: false
  }

  updateReceivingNotifications = () => {
    this.setState({ isReceivingNotifications: !this.state.isReceivingNotifications })
  }

  render() {
    const { name, profilePic, isReceivingNotifcations } = this.state;
    return (
      <div>
        <h2>{name}</h2>
        <img src={profilePic} />
        <input type="checkbox" checked={isReceivingNotifications} onChange={this.updateReceivingNotifications} />
      </div>
    );
  }
}

Simple, the component presentation is derived from the state of the component. If the isReceivingNotifcations is true, then the checkbox will be checked.

Let's look at this same example with the proposed design pattern:

class UserProfile extends Component {
  state = {
    name: 'Bob',
    profilePic: 'someurl.com/profile-pic',
    isReceivingNotifications: false
  }

  componentDidMount() {
    const checkBox = document.getElementById('my-checkbox');
    const that = this;
    // Use a regular function to bind the this context to the checkbox instead of component
    checkBox.addEventListener('change', function() {
      if (this.checked) {
         that.setState({ isReceivingNotifcations: true });
      } else {
         that.setState({ isReceivingNotifcations: false });
      }
    });
  }

  render() {
    const { name, profilePic, isReceivingNotifcations } = this.state;
    return (
      <div>
        <h2>{name}</h2>
        <img src={profilePic} />
        <input
          type="checkbox"
          checked={isReceivingNotifications}
          id="my-checkbox"
          />
       </div>
    );
  }
}

The first is much cleaner, no matter how you format this with jQuery or whatever DOM manipulation library you would use.

This is a contrived example, but every time I've seen some version of this in real life it's been quite a mess.

In the end, why?

Just take a bit of time and learn React design patterns. I'd suggest thinking in React. jQuery should be a last resort, as you're using React for a reason i'd assume.

One exception to this is jQuery libraries you use in React

In this case, you have no other option other than rewriting the library. As highlighted in this article you should write a wrapper component to make it React compliant.

like image 164
Josh Alexy Avatar answered Nov 14 '22 23:11

Josh Alexy