Props are the way to pass down data from a parent to a child component in React.
For this next example, we want to change the InvestmentListItem
component to render the value of the roi
variable formatted in percentage.
To implement the next specs, we are going to use a few helper methods that React offers through the React.addons.TestUtils
object, as follows:
describe("InvestmentListItem", function() { var TestUtils = React.addons.TestUtils; describe("given an Investment", function() { var investment, component; beforeEach(function() { investment = new Investment({ stock: new Stock({ symbol: 'peto', sharePrice: 0.25 }), shares: 100, sharePrice: 0.20 }); component = TestUtils.renderIntoDocument( <InvestmentListItem investment={investment}/> ); }); it("should render the return of investment as a percentage", function() { var roi = TestUtils.findRenderedDOMComponentWithClass(component, 'roi'), expect(roi.getDOMNode()).toHaveText('25%'), }); }); });
As you can see, we are no longer using the setFixture
method from the jasmine-jquery
matcher. Instead, we are using the TestUtils
module to render the component.
The biggest difference here is that TestUtils.renderIntoDocument
doesn't actually render in the document, but it renders into a detached node.
The next thing you will notice is that the InvestmentListItem
component has an attribute (actually called prop) where we pass down investment
.
Then, at the spec, we are using another helper method called findRenderedDOMComponentWithClass
to look for a DOM element in our component
variable.
This method returns ReactElement
. And again, we will use the getDOMNode
method to get the actual DOM element and then use the jasmine-jquery
matcher to check for its text value, as follows:
var roi = TestUtils.findRenderedDOMComponentWithClass(component, 'roi'),
expect(roi.getDOMNode()).toHaveText('25%'),
Implementing this behavior in the component is actually very simple:
(function (React) { var InvestmentListItem = React.createClass({ render: function () { var investment = this.props.investment; return <li className="investment-list-item"> <article> <span className="roi">{formatPercentage(investment.roi())}</span> </article> </li>; } }); function formatPercentage (number) { return (number * 100).toFixed(0) + '%'; } this.InvestmentListItem = InvestmentListItem; })(React);
We can access any props passed to a component through the this.props
object.
Expanding the original implementation, we've added a span
element with the expected class from the spec.
To allow the return on investment to be dynamic, JSX has a special syntax. Using {}
, you can invoke any JavaScript code in the middle of the XML. We are invoking the formatPercentage
function while passing the investment.roi()
value, as follows:
<span className="roi">{formatPercentage(investment.roi())}</span>
Again, just to make this clear, this JSX transformed into JavaScript would be:
React.createElement("span", {className: "roi"}, formatPercentage(investment.roi()))
It is important to know that a prop should be immutable. It is not the responsibility of a component to change its own prop values. You can consider a React component that has only props as a pure function, in that it always returns the same result value given the same argument values.
This makes testing very simple as there are no mutations or changes in the state to test a component.