=========================== 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 ``