在React中正确使用Jquery的方法是什么?

19

我正在处理一个使用了大量jQuery的布局/模板项目。

我已经学会了如何将该模板与ReactJS项目集成,但是我正在寻找一种完全替代jQuery的解决方案。

我的其中一个解决方案是在React的ComponentDidMount()Render()函数中使用jQuery函数。

这种方法正确吗? 这是正确的方式吗?

我在下面附上了一个小例子:

import React, { Component } from 'react';
import '../stylesheets/commonstyles.css';
import '../stylesheets/bootstrap-sidebar.css';
import '../stylesheets/sidebar1.css';
import $ from 'jquery';
 class NavBar extends Component {
   constructor(props){

      super(props);
      this.openSidebar = this.openSidebar.bind(this);

   }

  openSidebar(){

      console.log('hello sidebar');

  }
  componentWillMount(){

    $(document).ready(function () {
        $('#sidebarCollapse').on('click', function () {
            $('#sidebar').toggleClass('active');
        });
        $('.search-btn').on("click", function () {
          $('.search').toggleClass("search-open");
            return false;
           });

    });

}

这是我的渲染函数。

{/* <!--- SIDEBAR -------> */}
 <div class="wrapper" style={{paddingTop:60}}>
           {/* <!-- Sidebar Holder --> */ }
            <nav id="sidebar">
                <div class="sidebar-header">
                    <h3>Dashboard</h3>
                    <strong>BS</strong>
                </div>

                <ul class="list-unstyled components">
                    <li class="active">
                        <a href="#homeSubmenu" /*data-toggle="collapse" */ aria-expanded="false">
                            <i class="ti-home"></i>
                            Home
                        </a>
                        <ul class="collapse list-unstyled" id="homeSubmenu">
                            <li><a href="#">Home 1</a></li>
                            <li><a href="#">Home 2</a></li>
                            <li><a href="#">Home 3</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-align-justify" ></i>
                            About
                        </a>
                        <a href="#pageSubmenu" /*data-toggle="collapse" */ aria-expanded="false" style={{color:"white"}}>
                            <i class="ti-text"></i>
                            Pages
                        </a>
                        <ul class="collapse list-unstyled" id="pageSubmenu">
                            <li><a href="#">Page 1</a></li>
                            <li><a href="#">Page 2</a></li>
                            <li><a href="#">Page 3</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-paragraph"></i>
                            Portfolio
                        </a>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-control-play"></i>
                            FAQ
                        </a>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-share-alt"></i>
                            Contact
                        </a>
                    </li>
                </ul>
            </nav>

            { /* <!-- Page Content Holder --> */ }
            <div id="content">  


            </div>
        </div>

8
不要这样做。使用jQuery或React,不要同时使用两者(同样适用于Angular或Vue)。 - Jeremy Thille
1
不是因为那并没有明确解决 OP 的问题,也没有让他们的代码工作。他们需要完全重写所有内容并放弃 jQuery,但我不会在我的答案中这样做 :) - Jeremy Thille
1
正如Jeremy所说,你不应该在React中使用jQuery。在你的例子中,你正在使用jQuery直接将js函数挂载到dom中。任何直接的dom操作通常都是一个非常糟糕的想法,并最终会导致糟糕的渲染和事物的消失,因为状态发生了改变。 - Fantastisk
2
移除Jquery,使用React状态替换您的点击切换,就像这个答案所示:https://dev59.com/iVgQ5IYBdhLWcg3whEVn - Rence
2
@JeremyThille的评论应该是答案。此外,如果此组件在某个时候重新挂载,它将有许多僵尸事件,使您的应用程序变得越来越慢。为了防止这种情况,请不要忘记使用$.off。但是,由于css3/webpack/querySelector/querySelectorAll/ReactJS/vue/...的原因,许多用户认为jQuery已被弃用,因此您不应该使用它。 - Dimitri Kopriwa
显示剩余4条评论
5个回答

42

这种方法正确吗?它是正确的方式吗?

不。没有任何一种方法是正确的,也没有一种正确的方式同时使用jQuery和React/Angular/Vue。

jQuery通过选择元素并添加/删除它们中的内容来操作DOM。通常,它会选择一个现有的<div>并设置其文本。

其他框架不会操作DOM;它们会根据数据生成DOM,并在数据更改后重新生成DOM(例如,在Ajax调用之后)。

问题是,jQuery对React的存在和操作一无所知,而React对jQuery的存在和操作也一无所知。

这必然会导致一个破碎的应用程序,充满了hack和workaround,难以维护,更不用说你需要加载两个库而不是一个。

例如,jQuery会选择一个<button>并添加一个.click()监听器;但是在片刻之后,React/Angular/Vue可能会重新生成DOM和按钮,使jQuery的.click()失效。于是你会在Stackoverflow上发问,想知道为什么你的.click()不起作用。最终你会添加一个肮脏的setTimeout() hack,延迟jQuery的click()处理程序直到React重新生成你的按钮。这是直接走向地狱的大道。

解决方案:使用jQuery或(React / Angular / Vue)中的一个,不要同时使用两个。


12
虽然你对于 jQuery 和 React 彼此干扰状态的可能性是正确的,但我认为说这两个必须不能一起使用是不正确的。只要它们不被错误地混合在一起,一个应用程序可以同时拥有两者。请更新您的答案,Jeremy。增量地将 React 添加到您的堆栈中没有任何问题。 - user2065736
谢谢。我在想,那么如何替换jQuery提供的动画、饼图和其他元素呢?你可以轻松地替换jQuery的元素切换功能,但是动画和其他元素,应该使用Vanilla JS或另一个框架来将这些jQuery函数转换为模板,并使用React进行优化。 - codemt
1
你说过“jQuery 操纵 DOM”。不是这样的。你可以让 jQuery 去做它。你可以用很多种方式使用 jQuery。所以,答案不应该是“不行”。这取决于情况。如果开发者知道自己在做什么,两种方法都可以使用。 - gulima
3
React文档介绍了如何正确地混合使用其他库:https://reactjs.org/docs/integrating-with-other-libraries.html。 - ADJenks
安装后,如果使用jQuery进行幻灯片/动画目的,会出现什么问题?两者都会得到原始DOM。?? - Sobhani

3

这种方法正确吗?是正确的方式吗?

不是的。不要使用jQuery来给React创建和管理的DOM元素附加事件监听器。使用onClick。我在你的片段中找不到#sidebarCollapse。它可能看起来像这样。

<button id="sidebarCollapse" onClick={state => this.setState({ collapsed: !state.collapsed })>Collapse</button

侧边栏的 <nav id="sidebar"> 的类可能取决于此状态

<nav id="sidebar" className={ this.state.collapsed ? "": "active" } >

您会注意到,您将添加、删除类、属性和其他DOM操作的运行操作交给React,并声明如何根据状态更改来反映事物。在此过程中,如果您尝试运行jQuery操作,则您的UI可能会处于不一致状态。
迁移可以这样完成:用React替换UI元素的部分。例如,最初您可以执行以下操作,
<!-- rest of your existing jQuery based code -->
<header id="reactManagedNavbar">
  <!-- Nothing here. React will take care of DOM Elements here -->
</header>
<!-- rest of your existing jQuery based code -->

React 的代码可能如下所示:

// main.js
ReactDOM.render(<MyNavBar />, document.getElementById('reactManagedNavBar'))

// MyNavBar.js could have the react components

这样你就可以逐步迁移到React,并且仍然与jQuery并存。只是不要操纵彼此的DOM元素。

有时你需要在React组件中使用jQuery插件(动画,可视化图表等)。使用refs

class MyJQueryDependingComp extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  componentDidMount() {
    // this.myRef.current is the dom element. Pass it to jQuery
  }
  render() {
    return (
       {/* rest of React elements */}
       <div ref={this.myRef} />
       {/* rest of React elements */}
    );
  }
}

再次强调,不要在React中触及您的jQuery DOM,反之亦然。


0

我建议你在webpack.config中使用一个provider插件:

它非常简单易用,可以让你在项目中使用jQuery而无需在每个文件中导入该包:

更多信息文档: https://webpack.js.org/plugins/provide-plugin/

所以你只需要在webpack.config文件中添加这个插件:

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
});

0

没有真正的方法将Jquery模板转换为React模板,除非逐个选择地通过并在React中重写所有内容。原因是这两个库以不同的方式操作dom


-1

jQuery 和 React 可以很好地一起使用,但前提是它们彼此不干扰。如果您选择使用 jQuery,请仅使用 jQuery 来操作 DOM,而不要同时使用两者。另外一种方法是在 index.html 文件中的 React JS 文件之外使用 jQuery。 请注意:这仅在您查询的页面首先加载时才有效。


6
这个答案可能需要一些澄清,也许需要一个小的代码示例。 - user1531971

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接