Rendering jQuery UI widgets

The jQuery UI widget library implements several widgets on top of standard HTML. It uses a progressive enhancement technique whereby the basic HTML is enhanced in browsers that support newer features. To make these widgets work, you first need to render HTML into the DOM somehow; then, make imperative function calls to create and interact with the widgets.

In this example, you'll create a React button component that acts as a wrapper around the jQuery UI widget. Anyone using the React component shouldn't need to know that behind the scenes, it's making imperative calls to control the widget. Let's see what the button component looks like:

import React, { Component } from 'react';

// Import all the jQuery UI widget stuff...
import $ from 'jquery';
import 'jquery-ui/ui/widgets/button';
import 'jquery-ui/themes/base/all.css';

export default class MyButton extends Component {
// When the component is mounted, we need to
// call "button()" to initialize the widget.
componentDidMount() {
$(this.button).button(this.props);
}

// After the component updates, we need to use
// "this.props" to update the options of the
// jQuery UI button widget.
componentDidUpdate() {
$(this.button).button('option', this.props);
}

// Renders the "<button>" HTML element. The "onClick()"
// handler will always be a assigned, even if it's a
// noop function. The "ref" property is used to assign
// "this.button". This is the DOM element itself, and
// it's needed by the "componentDidMount()" and
// "componentDidUpdate()" methods.
render() {
return (
<button
onClick={this.props.onClick}
ref={button => {
this.button = button;
}}
/>
);
}
}

 

The jQuery UI button widget expects a <button> element, so this is what's rendered by the component. An onClick() handler from the component props is assigned as well. There's also a ref property used here, which assigns the button argument to this.button. The reason this is done is so that the component has direct access to the underlying DOM element of the component. Generally, components don't need access to any DOM elements, but here, you need to issue imperative commands to the element.

For example, in the componentDidMount() method,  the button() function is called and passes it properties from the component. The componentDidUpdate() method does something similar, which is called when property values change. Now, let's take a look at the button container component:

import React, { Component } from 'react';
import { fromJS } from 'immutable';

import MyButton from './MyButton';

class MyButtonContainer extends Component {
// The initial state is an empty Immutable map, because
// by default, we won't pass anything to the jQuery UI
// button widget.
state = {
data: fromJS({})
};

// Getter for "Immutable.js" state data...
get data() {
return this.state.data;
}

// Setter for "Immutable.js" state data...
set data(data) {
this.setState({ data });
}

// When the component is mounted for the first time,
// we have to bind the "onClick()" handler to "this"
// so that the handler can set the state.
componentDidMount() {
this.data = this.data.merge(this.props, {
onClick: this.props.onClick.bind(this)
});
}

// Renders the "<MyButton>" component with this
// component's state as properties.
render() {
return <MyButton {...this.state.data.toJS()} />;
}
}

// By default, the "onClick()" handler is a noop.
// This makes it easier because we can always assign
// the event handler to the "<button>".
MyButtonContainer.defaultProps = {
onClick: () => {}
};

export default MyButtonContainer;

You have a container component that controls the state, which is then passed to <MyButton> as properties.

The {...data} syntax is called JSX spread attributes. This allows you to pass objects to elements as attributes. You can read more about this feature here.

The component has a default onClick() handler function. But, you can pass a different click handler in as a property. Additionally, it's automatically bound to the component context, which is useful if the handler needs to change the button state. Let's look at an example of this:

import React from 'react';
import { render } from 'react-dom';

import MyButtonContainer from './MyButtonContainer';

// Simple button event handler that changes the
// "disabled" state when clicked.
function onClick() {
this.data = this.data.set('disabled', true);
}

render(
<section>
{/* A simple button with a simple label. */}
<MyButtonContainer label="Text" />

{/* A button with an icon, and a hidden label. */}
<MyButtonContainer
label="My Button"
icon="ui-icon-person"
showLabel={false}
/>

{/* A button with a click event handler. */}
<MyButtonContainer label="Disable Me" onClick={onClick} />
</section>,
document.getElementById('root')
);

Here, you have three jQuery UI button widgets, each controlled by a React component with no imperative code in sight. Here's how the buttons look:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.100.34