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

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

问题描述

如何在 React 中使用 jQuery UI?我在谷歌上看过几个例子,但似乎都过时了.

解决方案

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

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

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

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

<小时>

TLDR:最终版本

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

...另外,下面是从较长的注释中缩短的代码片段:

class Sortable 扩展 React.Component {componentDidMount() {this.$node = $(this.refs.sortable);this.$node.sortable({不透明度:this.props.opacity,改变:(事件,用户界面)=>this.props.onChange(event, ui)});}shouldComponentUpdate() { 返回假;}componentWillReceiveProps(nextProps) {if (nextProps.enable !== this.props.enable)this.$node.sortable(nextProps.enable ? 'enable' : 'disable');}渲染项目(){返回 this.props.data.map( (item, i) =><li key={i} className="ui-state-default"><span className="ui-icon ui-icon-arrowthick-2-n-s"></span>{ 物品 });}使成为() {返回 (<ul ref="sortable">{ this.renderItems() });}componentWillUnmount() {this.$node.sortable('destroy');}};

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

Sortable.defaultProps = {不透明度:1,启用:真};Sortable.propTypes = {不透明度:React.PropTypes.number,启用:React.PropTypes.bool,onChange:React.PropTypes.func.isRequired};

... 下面是如何使用 组件:

class MyComponent 扩展 React.Component {构造函数(道具){超级(道具);//使用这个标志来禁用/启用<Sortable/>this.state = { isEnabled: true };this.toggleEnableability = this.toggleEnableability.bind(this);}切换启用能力(){this.setState({ isEnabled: !this.state.isEnabled });}handleOnChange(事件,用户界面){console.log('DOM 改变了!', event, ui);}使成为() {const list = ['ReactJS', 'JSX', 'JavaScript', 'jQuery', 'jQuery UI'];返回 (<div><按钮类型=按钮"onClick={this.toggleEnableability}>切换启用/禁用<可排序的不透明度={0.8}数据={列表}启用={this.state.isEnabled}onChange={this.handleOnChange}/>

);}}ReactDOM.render(, document.getElementById('app'));

<小时>

完整说明

对于那些想要了解为什么如何的人.以下是分步指南:

第 1 步:创建一个组件.

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

class Sortable 扩展 React.Component {componentDidMount() {//每个 React 组件都有一个公开的函数//它正在包装的底层 DOM 节点.我们可以用那个//DOM 节点,将其传递给 jQuery 并初始化插件.//你会发现很多 jQuery 插件都遵循同样的模式//然后你就可以将组件 DOM 节点传递给 jQuery//并调用插件函数.//获取DOM节点并存储jQuery元素引用this.$node = $(this.refs.sortable);//初始化你需要的 jQuery UI 功能//在这种情况下,Sortable:https://jqueryui.com/sortable/this.$node.sortable();}//jQuery UI sortable 需要一个 <ul>带有 
  • 的列表.渲染项目(){返回 this.props.data.map( (item, i) =><li key={i} className="ui-state-default"><span className="ui-icon ui-icon-arrowthick-2-n-s"></span>{ 物品 }
  • );}使成为() {返回 (<ul ref="sortable">{ this.renderItems() });}};

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

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

    class Sortable 扩展 React.Component {//... 为简洁起见省略componentDidMount() {this.$node = $(this.refs.sortable);this.$node.sortable({//获取传入的 `opacity` 属性并在插件配置中使用它不透明度:this.props.opacity,});}//... 为简洁起见省略};//可选:设置默认道具,以防没有传递Sortable.defaultProps = {不透明度:1};

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

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

    第 3 步:插件事件的关联函数.

    您很可能需要连接一些插件方法,以执行一些 React 逻辑,例如,操作状态 let's day.

    这是如何做到的:

    class Sortable 扩展 React.Component {//... 为简洁起见省略componentDidMount() {this.$node = $(this.refs.sortable);this.$node.sortable({不透明度:this.props.opacity,//获取传入的onChange函数//并在 Sortable `change` 事件上调用它改变:(事件,用户界面)=>this.props.onChange(event, ui)});}//... 为简洁起见省略};//可选:设置道具类型Sortable.propTypes = {onChange:React.PropTypes.func.isRequired};

    这里是如何使用它:

    <可排序不透明度={0.8}onChange={ (event, ui) =>console.log('DOM 已更改!', event, ui) }/>

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

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

    React 生命周期方法来救援!

    使用 shouldComponentUpdate() 让 React 知道组件的输出是否不受当前 state 或 props 变化的影响.默认行为是在每次状态更改时重新渲染,并且在绝大多数情况下,但我们不希望这种行为!

    shouldComponentUpdate() 在接收新道具或状态时在渲染之前调用.如果 shouldComponentUpdate() 返回 false,则 componentWillUpdate()render()componentDidUpdate() 不会被调用.

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

    class Sortable 扩展 React.Component {//强制组件的单一渲染,//通过从 shouldComponentUpdate ReactJS 生命周期钩子返回 false.//在 ReactJS 在实际 DOM 中添加元素之后,//我们需要将未来的控制权传递给 jQuery.//这样,ReactJS 将永远不会重新渲染我们的组件,//jQuery 将负责所有更新.应该组件更新(){返回假;}componentWillReceiveProps(nextProps) {//每次组件接收到新的 props 时,//我们应该触发刷新或执行我们需要的任何其他操作.//对于这个例子,我们将只更新启用/禁用选项,//一旦我们收到 this.props.enable 的不同值if (nextProps.enable !== this.props.enable) {this.$node.sortable(nextProps.enable ? 'enable' : 'disable');}}//... 为简洁起见省略};//可选:设置默认道具,以防没有传递Sortable.defaultProps = {启用:真};//可选:设置道具类型Sortable.propTypes = {启用:React.PropTypes.bool};

    第 5 步:清理混乱.

    许多 jQuery 插件提供了一种机制,用于在不再需要时自行清理.jQuery UI Sortable 提供了一个我们可以触发的事件,告诉插件解除其 DOM 事件的绑定并销毁.React 生命周期方法再次派上用场,并提供了在组件卸载时挂钩的机制.

    class Sortable 扩展 React.Component {//... 为简洁起见省略componentWillUnmount() {//当组件卸载时清理混乱this.$node.sortable('destroy');}//... 为简洁起见省略};

    结论

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

    在库修改 DOM 的情况下,我们尽量让 React 不受影响.当 React 完全控制 DOM 时,它的效果最好.在这些情况下,React 组件更像是 3rd 方库的包装器.主要是通过使用 componentDidMount/componentWillUnmount 来初始化/销毁第三方库.和 props 作为一种方式,让父级自定义子级包装的第三方库的行为并连接插件事件.

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

    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.

    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:

    • 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.

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


    TLDR: The Final Version

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

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

    ... 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:

    Step 1: Create a component.

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

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

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

    Step 3: Hook-up functions on plugin events.

    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.

    Here's how to do that:

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

    And here's how to use it:

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

    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!

    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() 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.

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

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

    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.

    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.

    You can use this approach to integrate almost any jQuery plugin!

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

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