带有 React 的 jQuery 选择器可以吗?

IT技术 javascript jquery reactjs
2021-05-02 08:00:24

我知道混合使用 jQuery 和 ReactJS 是不可取的,因为 ReactJS 不知道 jQuery 对 DOM 所做的任何修改。但是,如果您只使用 jQuery 来轻松方便地查询 DOM 和查找节点,而将所有 DOM 编辑留给 ReactJS,那该怎么办?除了 jQuery 是一个大库之外,还有其他缺点吗?

一个示例用例是在下拉菜单组件安装时设置事件侦听器,以检查用户是否单击菜单外的任何位置,以便菜单可以关闭。jQuery.parents()方法是一种非常方便的方法来检查单击目标是否是菜单容器元素的子级。有一种简单的方式来做到这一点ReactJS还是有vanilla JavaScript

这是此示例的代码示例:

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)
  }
}
2个回答

是的,我会说在 React 中使用 jQuery 有缺点。

VDOM diffing 算法会混淆

这是你提到的一个。是的,如果您只使用read-only属性会很好,但除非您针对的是较旧的浏览器,否则document.querySelector重量会更轻。

您引入的每个依赖项,尤其是像图书馆一样大的依赖项,都应该经过仔细审查。详情见肥胖流行网站

此外,“我只会将它用于阅读,剩下的交给 React”的想法会给您的代码增加一层明显的混乱,我们将在下一个示例中看到。

你放弃了 React 的模式

在我看来,更大的问题是放弃 React 的模式。用一句话来描述 React,我会说:

React 是一个基于组件的库,用于从state输入生成 HTML、CSS 和 JavaScript 功能

假设我有一个简单的UserProfile组件。这个组件会有一些关于用户的数据,包括一个是否接收推送通知的开关:

// 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>
    );
  }
}

很简单,组件的表现是从组件的状态派生出来的。如果isReceivingNotifcations为真,则复选框将被选中。

让我们用建议的设计模式来看看这个相同的例子:

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>
    );
  }
}

第一个更简洁,无论您如何使用 jQuery 或您将使用的任何 DOM 操作库对其进行格式化。

这是一个人为的例子,但每次我在现实生活中看到它的某个版本时,它都是一团糟。

最后,为什么?

花点时间学习 React 设计模式。我建议在 React 中思考jQuery 应该是最后的手段,因为我认为您使用 React 是有原因的。

一个例外是你在 React 中使用的 jQuery 库

在这种情况下,除了重写库之外别无选择。正如本文所强调的,您应该编写一个包装器组件以使其符合 React。

我说您的问题归结为是否正确:可以查询浏览器 DOM 以获取您将在 React 中使用的信息吗?由于虚拟 DOM 始终与浏览器 DOM 同步,因此在浏览器 DOM 中进行只读查找当然也不错。事实上,如果您想添加交互性或用户事件处理,您有时需要在浏览器 DOM 而非虚拟 DOM 上执行此操作。

然后至于使用哪个库:除了 jQuery 之外,还有更轻量的选项,比如 minifiedjs。