You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[react-scripts-ts](https://www.npmjs.com/package/react-scripts-ts) is a set of adjustments to take the standard create-react-app project pipeline and bring TypeScript into the mix.
30
30
31
-
At this point, your project layout should more or less look something like the following:
31
+
At this point, your project layout should look like the following:
32
32
33
33
```text
34
34
my-app/
@@ -58,7 +58,7 @@ Running the project is as simple as running
58
58
npm run start
59
59
```
60
60
61
-
This runs the `start` script specified in our `package.json`, and will spawn off a server reacts to updates as we save our files.
61
+
This runs the `start` script specified in our `package.json`, and will spawn off a server which reloads the page as we save our files.
62
62
Typically the server runs at `http://localhost:3000`, but should be automatically opened for you.
63
63
64
64
This tightens the iteration loop by allowing us to quickly preview changes.
@@ -77,9 +77,9 @@ If you'd like, you can run `npm run start` and `npm run test` side by side so th
77
77
78
78
# Creating a production build
79
79
80
-
When running the project (as specified earlier), we didn't end up with an optimized build.
80
+
When running the project with `npm run start`, we didn't end up with an optimized build.
81
81
Typically, we want the code we ship to users to be as fast and small as possible.
82
-
Certain optimizations (like minification) can accomplish this, but often take more time.
82
+
Certain optimizations like minification can accomplish this, but often take more time.
83
83
We call builds like this "production" builds (as opposed to development builds).
84
84
85
85
To run a production build, just run
@@ -90,7 +90,8 @@ npm run build
90
90
91
91
This will create an optimized JS and CSS build in `./build/static/js` and `./build/static/css` respectively.
92
92
93
-
You won't need to run a production build most of the time, but it's often useful to do so before committing changes.
93
+
You won't need to run a production build most of the time,
94
+
but it is useful if you need to measure things like the final size of your app.
Notice that we defined a type named `Props` that specifies the properties our component will take.
140
141
`name` is a required `string`, and `enthusiasmLevel` is an optional `number` (which you can tell from the `?` that we wrote out after its name).
141
142
142
143
We also wrote `Hello` as a stateless function component (an SFC).
143
-
To be specific, `Hello` is a variable being assigned an arrow function.
144
-
That arrow function destructures a given`Props` object, and defaults `enthusiasmLevel` to `1` if it isn't defined.
144
+
To be specific, `Hello` is a function that takes a `Props` object, and destructures it.
145
+
If `enthusiasmLevel` isn't given in our`Props` object, it will default to `1`.
145
146
147
+
Writing functions is one of two primary [ways React allows us to make components]((https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components)).
146
148
If we wanted, we *could* have written it out as a class as follows:
But we don't really need to think about state in this example - in fact, we specified it as `undefined` in `React.Component<Props, undefined>`, so writing an SFC tends to be shorter.
170
+
But we don't really need to think about state in this example - in fact, we specified it as `object` in `React.Component<Props, object>`, so writing an SFC tends to be shorter.
169
171
We will revisit how to bind global application state with Redux in a bit, but local component state is more useful at the presentational level when creating generic UI elements that can be shared between libraries.
170
172
171
-
Now that we've written our component, let's replace our render of `<App />` with a render of `<Hello ... />`.
173
+
Now that we've written our component, let's dive into `index.tsx` and replace our render of `<App />` with a render of `<Hello ... />`.
172
174
173
-
First we'll import it.
175
+
First we'll import it at the top of the file:
174
176
175
177
```ts
176
178
importHellofrom'./components/Hello.tsx';
@@ -206,7 +208,7 @@ To style our `Hello` component, we can create a CSS file at `src/components/Hell
206
208
}
207
209
```
208
210
209
-
The tools that create-react-app uses (namely, Webpack and various loaders) allow us to simply import the stylesheets we're interested in.
211
+
The tools that create-react-app uses (namely, Webpack and various loaders) allow us to import the stylesheets we're interested in.
210
212
So in `src/components/Hello.tsx`, we'll add the following import.
211
213
212
214
```ts
@@ -224,9 +226,10 @@ Let's reiterate what they were:
224
226
225
227
We can use these requirements to write a few tests for our components.
226
228
227
-
But first, let's add our first dependency.
228
-
Enzyme is a common tool in the React ecosystem that makes it easier to write tests for how components will behave.
229
-
While we have jsdom support available to emulate how a component will act in the DOM, Enzyme makes it easier to make certain queries about our components.
229
+
But first, let's install Enzyme.
230
+
[Enzyme](http://airbnb.io/enzyme/) is a common tool in the React ecosystem that makes it easier to write tests for how components will behave.
231
+
By default, our application includes a library called jsdom to allow us to simulate the DOM and test its runtime behavior without a browser.
232
+
Enzyme is similar, but builds on jsdom and makes it easier to make certain queries about our components.
230
233
231
234
Let's install it as a development-time dependency.
Notice we installed packages `enzyme` as well as `@types/enzyme`.
238
241
The `enzyme` package refers to the package containing JavaScript code that actually gets run, while `@types/enzyme` is a package that contains declaration files (`.d.ts` files) so that TypeScript can understand how you can use Enzyme.
242
+
You can learn more about `@types` packages [here](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html).
243
+
239
244
We also had to install `react-addons-test-utils`.
240
-
`enzyme` actually expects `jsdom` and `react-addons-test-utils`to be installed, but we already have the former, and the latter may be optional for older versions of React.
245
+
This is something `enzyme` expects to be installed.
241
246
242
-
Now that we've got Enzyme installed, let's start writing our test!
247
+
Now that we've got Enzyme set up, let's start writing our test!
243
248
Let's create a file named `src/components/Hello.test.tsx`, adjacent to our `Hello.tsx` file from earlier.
244
249
245
250
```ts
@@ -292,16 +297,15 @@ As far as a React component is concerned, data flows down through its children t
292
297
293
298
As an answer, the React community relies on libraries like Redux and MobX.
294
299
295
-
[Redux](http://redux.js.org) relies on synchronizing data through a centralized immutable store of data, and updates to that data will trigger a re-renders to parts of the application.
300
+
[Redux](http://redux.js.org) relies on synchronizing data through a centralized and immutable store of data, and updates to that data will trigger a re-render our application.
296
301
State is updated in an immutable fashion by sending explicit action messages which must be handled by functions called reducers.
297
-
Because of the explicit nature, it may often be easier to reason about how an action will affect the state of your program.
302
+
Because of the explicit nature, it is often be easier to reason about how an action will affect the state of your program.
298
303
299
304
[MobX](https://mobx.js.org/) relies on functional reactive patterns where state is wrapped through observables and and passed through as props.
300
-
State is updated in a very natural way through traditional assignments that one would typically write in JavaScript.
301
305
Keeping state fully synchronized for any observers is done by simply marking state as observable.
302
306
As a nice bonus, the library is already written in TypeScript.
303
307
304
-
Both have different advantages and merits, with certain tradeoffs.
308
+
There are various merits and have tradeoffs to both.
305
309
Generally Redux tends to see more widespread usage, so for the purposes of this tutorial, we'll focus on adding Redux;
306
310
however, you should feel encouraged to explore both.
307
311
@@ -389,7 +393,7 @@ We've created two types that describe what increment actions and decrement actio
389
393
We also created a type (`EnthusiasmAction`) to describe cases where an action could be an increment or a decrement.
390
394
Finally, we made two functions that actually manufacture the actions.
391
395
392
-
There's some clear boilerplate here, so you should feel free to look into libraries like [redux-actions](https://www.npmjs.com/package/redux-actions) once you've got the hang of things.
396
+
There's clearly boilerplate here, so you should feel free to look into libraries like [redux-actions](https://www.npmjs.com/package/redux-actions) once you've got the hang of things.
393
397
394
398
## Adding a reducer
395
399
@@ -421,7 +425,9 @@ Notice that we're using the *object spread* (`...state`) which allows us to crea
421
425
It's important that the `enthusiasmLevel` property come last, since otherwise it would be overridden by the property in our old state.
422
426
423
427
You may want to write a few tests for your reducer.
424
-
It should be relatively easy. since reducers are pure functions, and can be passed arbitrary data.
428
+
Since reducers are pure functions, they can be passed arbitrary data.
429
+
For every input, reducers can tested by checking their newly produced state.
430
+
Consider looking into Jest's [toEqual](https://facebook.github.io/jest/docs/expect.html#toequalvalue) method to accomplish this.
@@ -562,7 +568,7 @@ const store = createStore<StoreState>(enthusiasm, {
562
568
563
569
`store` is, as you might've guessed, our central store for our application's global state.
564
570
565
-
Next, we're going to swap our our use of `./src/components/Hello` with `./src/containers/Hello` and use react-redux's `Provider` to wire up our props with our container.
571
+
Next, we're going to swap our use of `./src/components/Hello` with `./src/containers/Hello` and use react-redux's `Provider` to wire up our props with our container.
566
572
We'll import each:
567
573
568
574
```ts
@@ -583,6 +589,18 @@ ReactDOM.render(
583
589
584
590
Notice that `Hello` no longer needs props, since we used our `connect` function to adapt our application's state for our wrapped `Hello` component's props.
585
591
592
+
### Type assertions
593
+
594
+
One final thing we'll point out in this section is the line `document.getElementById('root') as HTMLElement`.
595
+
This syntax is called a *type assertion*, often also just called a *cast*.
596
+
This is a useful way of telling TypeScript that you know a little more about the type than the type checker does.
597
+
598
+
The reason we need to do so in this case is that `getElementById`'s return type is `HTMLElement | null`, meaning that it can return `null`.
599
+
We're operating under the assumption that `getElementById` will actually succeed, so we need convince TypeScript of that using the `as` syntax.
600
+
601
+
TypeScript also has a trailing "bang" (`!`) syntax, which removes `null` and `undefined` from the prior expression.
602
+
So we *could* have written `document.getElementById('root')!`, but in this case we wanted to be a bit more explicit.
603
+
586
604
# Ejecting
587
605
588
606
If at any point, you feel like there are certain customizations that the create-react-app setup has made difficult, you can always opt-out and get the various configuration options you need.
0 commit comments