如何在React JS中使用jQuery UI

Tah*_*sin 45 jquery-ui reactjs

如何在React中使用jQuery UI?我在Googling看过几个例子,但所有这些例子似乎都已经过时了.

Kal*_*sev 84

如果你真的需要这样做,这是我正在使用的方法.

计划:创建一个组件来管理jQuery插件.该组件将提供jQuery组件的以React为中心的视图.而且,它将:

  • 使用React生命周期方法初始化和拆除jQuery插件;
  • 使用React props作为插件配置选项并连接到插件的方法事件;
  • 组件卸载时销毁插件.

让我们通过jQuery UI Sortable插件探索一个如何实现这一目的的实际示例.


TLDR:最终版本

如果您只想获取包装的jQuery UI Sortable示例的最终版本:

...另外,下面是较长的评论代码片段缩短了:

class Sortable extends React.Component {
    componentDidMount() {
        this.$node = $(this.refs.sortable);
        this.$node.sortable({
            opacity: this.props.opacity,
            change: (event, ui) => this.props.onChange(event, ui)
        });
    }

    shouldComponentUpdate() { return false; }

    componentWillReceiveProps(nextProps) {
        if (nextProps.enable !== this.props.enable)
            this.$node.sortable(nextProps.enable ? 'enable' : 'disable');
    }

    renderItems() {
        return this.props.data.map( (item, i) =>
            <li key={i} className="ui-state-default">
                <span className="ui-icon ui-icon-arrowthick-2-n-s"></span>
                { item }
            </li>
        );
    }
    render() {
        return (
            <ul ref="sortable">
                { this.renderItems() }
            </ul>
        );
    }

    componentWillUnmount() {
        this.$node.sortable('destroy');
    }
};
Run Code Online (Sandbox Code Playgroud)

(可选)您可以设置默认道具(在没有传递的情况下)和道具类型:

Sortable.defaultProps = {
    opacity: 1,
    enable: true
};

Sortable.propTypes = {
    opacity: React.PropTypes.number,
    enable: React.PropTypes.bool,
    onChange: React.PropTypes.func.isRequired
};
Run Code Online (Sandbox Code Playgroud)

...以下是如何使用该<Sortable />组件:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
        // Use this flag to disable/enable the <Sortable />
        this.state = { isEnabled: true };

        this.toggleEnableability = this.toggleEnableability.bind(this);
    }

    toggleEnableability() {
        this.setState({ isEnabled: ! this.state.isEnabled });
    }

    handleOnChange(event, ui) {
        console.log('DOM changed!', event, ui);
    }

    render() {
        const list = ['ReactJS', 'JSX', 'JavaScript', 'jQuery', 'jQuery UI'];

        return (
            <div>
                <button type="button"
                    onClick={this.toggleEnableability}>
                    Toggle enable/disable
                </button>
                <Sortable
                    opacity={0.8}
                    data={list}
                    enable={this.state.isEnabled}
                    onChange={this.handleOnChange} />
            </div>
        );
    }
}

ReactDOM.render(<MyComponent />, document.getElementById('app'));
Run Code Online (Sandbox Code Playgroud)

完整解释

对于那些想要了解原因方式的人.这是一步一步的指南:

第1步:创建一个组件.

我们的组件将接受项目(字符串)的数组(列表)作为dataprop.

class Sortable extends React.Component {
    componentDidMount() {
        // Every React component has a function that exposes the
        // underlying DOM node that it is wrapping. We can use that
        // DOM node, pass it to jQuery and initialize the plugin.

        // You'll find that many jQuery plugins follow this same pattern
        // and you'll be able to pass the component DOM node to jQuery
        // and call the plugin function.

        // Get the DOM node and store the jQuery element reference
        this.$node = $(this.refs.sortable);

        // Initialize the jQuery UI functionality you need
        // in this case, the Sortable: https://jqueryui.com/sortable/
        this.$node.sortable();
    }

    // jQuery UI sortable expects a <ul> list with <li>s.
    renderItems() {
        return this.props.data.map( (item, i) =>
            <li key={i} className="ui-state-default">
                <span className="ui-icon ui-icon-arrowthick-2-n-s"></span>
                { item }
            </li>
        );
    }
    render() {
        return (
            <ul ref="sortable">
                { this.renderItems() }
            </ul>
        );
    }
};
Run Code Online (Sandbox Code Playgroud)

第2步:通过道具传递配置选项

假设我们想要在排序时配置帮助程序的不透明度.我们将使用opacity的插件配置,从取值选项0.011.

class Sortable extends React.Component {
    // ... omitted for brevity

    componentDidMount() {
        this.$node = $(this.refs.sortable);

        this.$node.sortable({
            // Get the incoming `opacity` prop and use it in the plugin configuration
            opacity: this.props.opacity,
        });
    }

    // ... omitted for brevity
};

// Optional: set the default props, in case none are passed
Sortable.defaultProps = {
    opacity: 1
};
Run Code Online (Sandbox Code Playgroud)

以下是我们现在可以在代码中使用该组件的方法:

<Sortable opacity={0.8} />
Run Code Online (Sandbox Code Playgroud)

同样,我们可以映射任何jQUery UI Sortable选项.

第3步:插件事件的连接功能.

你很可能需要连接一些插件方法,以便执行一些React逻辑,例如,操纵状态让我们一天.

以下是如何做到这一点:

class Sortable extends React.Component {
    // ... omitted for brevity

    componentDidMount() {
        this.$node = $(this.refs.sortable);

        this.$node.sortable({
            opacity: this.props.opacity,
            // Get the incoming onChange function
            // and invoke it on the Sortable `change` event
            change: (event, ui) => this.props.onChange(event, ui)
        });
    }

    // ... omitted for brevity
};

// Optional: set the prop types
Sortable.propTypes = {
    onChange: React.PropTypes.func.isRequired
};
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它:

<Sortable
    opacity={0.8}
    onChange={ (event, ui) => console.log('DOM changed!', event, ui) } />
Run Code Online (Sandbox Code Playgroud)

第4步:将未来的更新控制传递给jQuery

在ReactJS在实际DOM中添加元素之后,我们需要将未来的控制传递给jQuery.否则,ReactJS永远不会重新渲染我们的组件,但我们不希望这样.我们希望jQuery负责所有更新.

React生命周期方法得到了拯救!

使用shouldComponentUpdate()让React知道组件的输出是否不受当前状态或道具更改的影响.默认行为是在每次状态更改时重新呈现,在绝大多数情况下,但我们不希望出现此行为!

shouldComponentUpdate()在收到新的道具或州时,在渲染之前调用.如果shouldComponentUpdate()返回false,则componentWillUpdate(),render()和,componentDidUpdate()将不会被调用.

然后,我们使用componentWillReceiveProps(),我们比较this.propsnextProps和调用jQuery UI的排序更新只在必要时.对于此示例,我们将实现jQuery UI Sortable的enable/disable选项.

class Sortable extends React.Component {
    // Force a single-render of the component,
    // by returning false from shouldComponentUpdate ReactJS lifecycle hook.
    // Right after ReactJS adds the element in the actual DOM,
    // we need to pass the future control to jQuery.
    // This way, ReactJS will never re-render our component,
    // and jQuery will be responsible for all updates.
    shouldComponentUpdate() {
        return false;
    }

    componentWillReceiveProps(nextProps) {
        // Each time when component receives new props,
        // we should trigger refresh or perform anything else we need.
        // For this example, we'll update only the enable/disable option,
        // as soon as we receive a different value for this.props.enable
        if (nextProps.enable !== this.props.enable) {
            this.$node.sortable(nextProps.enable ? 'enable' : 'disable');
        }
    }

    // ... omitted for brevity
};

// Optional: set the default props, in case none are passed
Sortable.defaultProps = {
    enable: true
};

// Optional: set the prop types
Sortable.propTypes = {
    enable: React.PropTypes.bool
};
Run Code Online (Sandbox Code Playgroud)

第五步:清理乱七八糟的东西.

许多jQuery插件提供了一种在不再需要它们时自行清理的机制.jQuery UI Sortable提供了一个事件,我们可以触发该事件来告诉插件取消绑定其DOM事件并销毁.React生命周期方法再次得到拯救,并提供了一种在卸载组件时挂钩的机制.

class Sortable extends React.Component {
    // ... omitted for brevity

    componentWillUnmount() {
        // Clean up the mess when the component unmounts
        this.$node.sortable('destroy');
    }

    // ... omitted for brevity
};
Run Code Online (Sandbox Code Playgroud)

结论

用React包装jQuery插件并不总是最好的选择.但是,很高兴知道它是一个选项以及如何实现解决方案.如果您将遗留的jQuery应用程序迁移到React,或者您根本找不到适合您需要的React插件,那么这是一个可行的选择.

在库修改DOM的情况下,我们尝试使React不受影响.当React完全控制DOM时,React效果最佳.在这些情况下,React组件更像是第三方库的包装器.主要通过使用componentDidMount/componentWillUnmount来初始化/销毁第三方库.并且道具作为一种方式,为父母提供一种方法来定制孩子包装的第三方库的行为以及连接插件事件.

您可以使用此方法集成几乎任何jQuery插件!


Joh*_*ohn 12

React不能很好地发挥直接DOM突变的库.如果其他东西改变了React试图渲染的DOM,它将抛出错误.如果你必须使这项工作,你最好的妥协是让你的页面的不同部分由不同的东西管理,例如包含你的jquery组件的div,然后是包含你的React组件的一些其他div( S).然而,在这些不同的(jquery和react)组件之间进行通信将是困难的,而且老实说,选择其中一个可能更好.


Chi*_*uin 7

虽然技术上完美无缺,但Kayolan的答案有一个致命的缺陷,恕我直言:在将未来UI更新的责任从React传递给jQuery时,他反而忽略了React首先出现在那里的观点!React控制可排序列表的初始呈现,但在此之后,一旦用户执行第一次jQueryUI拖动/排序操作,React的状态数据就会过时.React的重点是在视图级别表示您的状态数据.

所以,当我解决这个问题时,我采取了相反的方法:我试图确保React尽可能地控制.我不让jQueryUI的可排序控制改变DOM 可言.

怎么可能?好吧,jQuery-ui的sortable()方法有一个cancel调用,可以将UI设置回你开始拖放之前的状态.诀窍是发出该cancel调用之前读取可排序控件的状态.这样,我们可以在调用之前将DOM设置回原来之前,了解用户的意图cancel.一旦我们有了这些意图,我们就可以将它们传递给React,并将状态数据操作为用户想要的新顺序.最后,在该数据上调用setState()以使React呈现新订单.

我是这样做的:

  1. 将jquery-ui.sortable()方法附加到行项列表(当然是由React生成的!)
  2. 让用户在DOM周围拖放这些行项目.
  3. 当用户开始拖动,我们看到用户的拖曳线项目的索引.
  4. 当用户删除订单项时,我们:
    1. 从jQuery-ui.sortable()读取行项目的新索引位置,即列表用户放置它的位置.
    2. cancel调用传递给jQuery-ui.sortable(),以使列表返回其原始位置,并且DOM保持不变.
    3. 将拖动的行项目的旧索引和新索引作为参数传递给React模块中的JavaScript函数.
    4. 让该函数将列表的后端状态数据重新排序为用户拖放它的新顺序.
    5. 进行React setState()通话.

UI中的列表现在将反映我们的状态数据的新顺序; 这是标准的React功能.

因此,我们可以使用jQueryUI Sortable的拖放功能,但是根本不需要更改DOM.React很高兴,因为它控制着DOM(它应该在哪里).

Github存储库示例位于https://github.com/brownieboy/react-dragdrop-test-simple.这包括现场演示的链接.

  • 我喜欢这两个答案。您的回答是我几年前如何实现 Knockout.js 和可排序的 jQuery UI 之间的集成,这让 KO 和虚拟 DOM 实现(如 React)都满意。另一方面,当我们无法取消第三方库的 DOM 更改时,很高兴知道我们有回退机制。 (2认同)

小智 5

我无法让 jquery-ui npm 包工作。对我有用的是使用 jquery-ui-bundle:

import $ from 'jquery';
import 'jquery-ui-bundle';
import 'jquery-ui-bundle/jquery-ui.min.css';
Run Code Online (Sandbox Code Playgroud)