如何在React JS中使用jQuery UI [英] How to use jQuery UI with React JS

查看:163
本文介绍了如何在React JS中使用jQuery UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在React中使用jQuery UI?我已经通过Googling看到了几个示例,但它们似乎都已经过时了.

How can I use jQuery UI with React? I have seen a couple examples by Googling, but all of them seem to be outdated.

推荐答案

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

If you really need to do that, here is an approach I am using.

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

The plan: Create a component to manage the jQuery plugin. This component will provide a React-centric view of the jQuery component. Moreover, it will:

  • 使用React生命周期方法来初始化和拆除jQuery插件;
  • 使用React props作为插件配置选项,并连接到插件的方法事件;
  • 卸载组件时销毁插件.
  • Use React lifecycle methods to initialize and tear down the jQuery plugin;
  • Use React props as plugin configuration options and hook up to plugin's methods events;
  • Destroy the plugin when component unmounts.

让我们探索一个实际的示例,该示例如何使用 jQuery UI Sortable 插件实现.

Let's explore a practical example how to do that with the jQuery UI Sortable plugin.

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

If you just want to grab the final version of the wrapped jQuery UI Sortable example:

  • here is a GIST I made with full annotated comments;
  • and here's a jsfiddle DEMO, full annotated comments too;

...加号,下面是从较长注释中缩短的代码段:

... plus, below is the shortened from the longer comments code snippet:

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

(可选)您可以设置默认道具(如果不传递任何道具)和道具类型:

Optionally, you can set default props (in the case of none are passed) and the prop types:

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

Sortable.propTypes = {
    opacity: React.PropTypes.number,
    enable: React.PropTypes.bool,
    onChange: React.PropTypes.func.isRequired
};

...以及使用<Sortable />组件的方法:

... and here's how to use the <Sortable /> component:

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


完整说明

对于那些想了解为什么如何的人.这是逐步指南:


The Full Explanation

For those of you, who want to understand why and how. Here's a step by step guide:

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

Our component will accept an array (list) of items (strings) as data prop.

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

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

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

Step 2: Pass configuration options via props

Let's say we want to configure the opacity of the helper while sorting. We'll use the opacity option in the plugin configuration, that takes values from 0.01 to 1.

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

这是我们现在如何在代码中使用组件的方法:

And here's how we can use the component in our code now:

<Sortable opacity={0.8} />

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

The same way, we can map any of the jQUery UI Sortable options.

您很可能需要连接一些插件方法,才能执行一些React逻辑,例如,操纵状态吧.

You will most probably need to hook-up on some of the plugin methods, in order to perform some React logic, for example, manipulate the state let's day.

操作方法如下:

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

这是使用方法:

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

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

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

Step 4: Pass the future updates control to jQuery

Right after ReactJS adds the element in the actual DOM, we need to pass the future control to jQuery. Otherwise, ReactJS will never re-render our component, but we don't want that. We want jQuery to be responsible for all updates.

反应生命周期方法来了!

React lifecycle methods comes to the rescue!

使用shouldComponentUpdate()来让React知道组件的输出是否不受状态或道具当前变化的影响.默认行为是在大多数状态变化时重新渲染每个状态,但绝大多数情况下,我们都不想这样做!

Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority, but we don't want this behavior!

shouldComponentUpdate().如果shouldComponentUpdate()返回false,则将不会调用componentWillUpdate()render()componentDidUpdate().

shouldComponentUpdate() is invoked before rendering when new props or state are being received. If shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate() will not be invoked.

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

Then, we use componentWillReceiveProps(), we compare this.props with nextProps and call jQuery UI sortable updates only when necessary. For this example, we will implement the enable/disable option of the jQuery UI Sortable.

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

第5步:清理烂摊子.

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

Step 5: Clean up the mess.

Many jQuery plugins provide a mechanism for cleaning up after themselves when they are no longer needed. jQuery UI Sortable provides an event that we can trigger to tell the plugin to unbind its DOM events and destroy. React lifecycle methods comes to the rescue again and provides a mechanism to hook into when the component is being unmounted.

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

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

    // ... omitted for brevity
};

结论

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

Conclusion

Wrapping jQuery plugins with React is not always the best choice. However, it is nice to know that it is an option and how you can implement a solution. It is a viable option if you are migrating a legacy jQuery application to React or maybe you just can't find a React plugin that suits your needs in your case.

在库修改DOM的情况下,我们尝试保持React的正常运行.当完全控制DOM时,React效果最佳.在这些情况下,React组件更多地是第三方库的包装器.通常,通过使用componentDidMount/componentWillUnmount初始化/销毁第三方库.以及props作为一种方式,为父母提供了一种方式来定制孩子包装的第三方库的行为并与插件事件挂钩.

In the case that a library modifies the DOM, we try to keep React out of its way. React works best when it has full control of the DOM. In these cases, React components are more of wrappers for the 3rd party libraries. Mostly by using the componentDidMount/componentWillUnmount to initialize/destroy the third party library. And props as a way of giving the parent a way of customizing the behavior of the third party library that the child wraps and to hook-up on plugin events.

您可以使用这种方法来集成几乎所有jQuery插件

这篇关于如何在React JS中使用jQuery UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆