===========================
Class Components With Props
===========================
In the previous step we made a "dumb" presentational component with one
property. In React, components can have properties and state. When they
have state (or when they need access to React's lifecycle methods), we use
a class-based component instead.
We're going to build a stateful counter component. Each click increments the
click count, with the current count value stored in local component state.
The ```` component will be passed in some props.
In this step, we'll show *class component* props -- as done with a function in
the previous step -- for class-based components. We'll do state in the next
step.
First a Test
============
This tutorial series shows component development using testing instead of a
browser. Let's write a broken test first, then do the implementation which
fixes the test.
Make a new file called ``Counter.test.tsx`` with this test:
.. code-block:: typescript
it('should render a counter', () => {
const wrapper = shallow();
expect(wrapper.find('.counter label').text())
.toBe('Count');
});
It has several failures. For now, just click on ``shallow`` and hit
``Alt-Enter`` to generate that import.
Now create a file ``Counter.tsx``. We'll make it very simple to start:
.. code-block:: jsx
import * as React from 'react';
class Counter extends React.Component {
public render() {
return (
1
);
}
}
export default Counter;
Back in our test, click on ```` and hit ``Alt-Enter``. Your import
is generated, but there's still an error: React isn't imported. Repeat the
``Alt-Enter`` to generate the React import. Save the file and see that your
test passes.
Not a bad first step.
Pass In a Prop
==============
As we did in the :doc:`previous section <../props/index>`, we'll do our
work first in the test. We'll write a failing test, then fix our "wrapper"
component, then fix the actual implementation. Also, we'll presume that the
component has a default label.
Thus, let's add a test for the case of passing in a label:
.. code-block:: typescript
it('should render a counter with custom label', () => {
const wrapper = shallow();
expect(wrapper.find('.counter label').text())
.toBe('Current');
});
The test fails, which is good. What's even better -- TypeScript helped us
"fail faster". Before running the test, it told us we broke the contract
saying no properties were expected. Even better, our IDE visually warned us
with a very specific mouseover message.
Let's now work on the implementation. Classes handle props with defaults a
little differently:
.. code-block:: typescript
class Counter extends React.Component<{ label?: string }> {
public static defaultProps = {
label: 'Count'
};
Remember the ``?`` means an optional field in the interface. Now make the
``