Component events

UI applications have user events; in the web, they came in the form of DOM events. As React wraps each DOM element into React elements, handling them will be a little different yet very familiar.

For this next example, let's suppose that our application will allow users to delete an investment. We could write this requirement through the following acceptance criterion:

Given an investment, InvestmentListItem should notify an observer onClickDelete when the delete button is clicked on.

The idea here is the same as presented in the Integrate Views with observers section of Chapter 3, Testing Frontend Code.

So, how should we set the observer in a component? As we've already seen previously, props are the way to pass attributes to our component, as follows:

describe("InvestmentListItem", function() {
  var TestUtils = React.addons.TestUtils;

  describe("given an Investment", function() {
    var investment, component, onClickDelete;

    beforeEach(function() {
      investment = new Investment({
        stock: new Stock({ symbol: 'peto', sharePrice: 0.25 }),
        shares: 100,
        sharePrice: 0.20
      });

      onClickDelete = jasmine.createSpy('onClickDelete'),

      component = TestUtils.renderIntoDocument(
        <InvestmentListItem investment={investment} onClickDelete={onClickDelete}/>
      );
    });

    it("should notify an observer onClickDelete when the delete button is clicked", function() {
      var deleteButton = TestUtils.findRenderedDOMComponentWithTag(component, 'button'),
      TestUtils.Simulate.click(deleteButton);
      expect(onClickDelete).toHaveBeenCalled();
    });

  });
});

As you can see, we passed down another prop to the onClickDelete component, and as its value, we set a Jasmine spy, as follows:

onClickDelete = jasmine.createSpy('onClickDelete'),

component = TestUtils.renderIntoDocument(
  <InvestmentListItem investment={investment} onClickDelete={onClickDelete}
/>
);

Then, we found the delete button through its tag and used the TestUtils module to simulate a click, expecting the previously created spy to be called, as follows:

var deleteButton = TestUtils.findRenderedDOMComponentWithTag(component, 'button'),
TestUtils.Simulate.click(deleteButton);
expect(onClickDelete).toHaveBeenCalled();

The TestUtils.Simulate module contains helper methods to simulate all types of DOM events, as follows:

TestUtils.Simulate.click(node);
TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}});
TestUtils.Simulate.keyDown(node, {key: "Enter"});

Then, we got back to the implementation:

(function (React) {
  var InvestmentListItem = React.createClass({
    render: function () {
      var investment = this.props.investment;
      var onClickDelete = this.props.onClickDelete;

      return <li className="investment-list-item">
        <article>
          <span className="roi">{formatPercentage(investment.roi())}</span>
          <button className="delete-investment" onClick={onClickDelete}>Delete</button>
        </article>
      </li>;
    }
  });

  function formatPercentage (number) {
    return (number * 100).toFixed(0) + '%';
  }

  this.InvestmentListItem = InvestmentListItem;
})(React);

As you can see, it was as simple as nesting another button component and passing down the onClickDelete prop value as its onClick prop.

React normalizes events so that they have consistent properties across different browsers, but its naming conventions and syntax is similar to inline JavaScript code in HTML. To get a comprehensive list of the supported events, you can check the official documentation at http://facebook.github.io/react/docs/events.html.

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

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