Merge branch 'master' of github.com:Microsoft/frontend-bootcamp

This commit is contained in:
Ken 2019-03-05 08:38:00 -08:00
Родитель a9d83d421f 49c15bdaa7
Коммит a2c2b0f3e9
53 изменённых файлов: 265 добавлений и 213 удалений

Просмотреть файл

@ -6,7 +6,7 @@
In this two-day workshop you'll learn the basics of frontend development while building a working web app. In this two-day workshop you'll learn the basics of frontend development while building a working web app.
The first day provides an introduction to the fundamentals of the web: HTML, CSS and JavaScript. This is targeted at new and experienced developers alike. On the second day we'll dive into more advanced topics like TypeScript, testing, and state management. While the examples should be accessible to anyone, you'll get the most out of it if you have some prior experience with programming and web technologies. The first day provides an introduction to the fundamentals of the web: HTML, CSS and JavaScript. This is targeted at new and experienced developers alike. On the second day we'll dive into more advanced topics like TypeScript, state management, and testing. While the examples should be accessible to anyone, you'll get the most out of it if you have some prior experience with programming and web technologies.
## Getting set up ## Getting set up
@ -23,88 +23,75 @@ Before starting, make sure your computer has up-to-date versions of the followin
### 2. Installing and opening the project ### 2. Installing and opening the project
- Open VS Code and then press `ctrl + ~` to open the built in terminal - Open VS Code and then press ```ctrl + ` ``` (backtick, in top left corner of keyboard) to open the built-in terminal
- Use the `cd` (change directory) command to find an appropriate place for your code - Use the `cd` (change directory) command to find an appropriate place for your code
- Type `git clone https://github.com/Microsoft/frontend-bootcamp.git` into the terminal, this will pull down a copy of the workshop code - Type `git clone https://github.com/Microsoft/frontend-bootcamp.git` into the terminal to pull down a copy of the workshop code
- Type `cd frontend-bootcamp` to change your current directory to the bootcamp folder - Type `cd frontend-bootcamp` to change your current directory to the bootcamp folder
- Type `npm install` to install of the project dependencies - Type `npm install` to install all of the project dependencies
- Type `code ./` to open the bootcamp code in VS Code - Type `code -r .` to open the bootcamp code in VS Code
> If on a Mac, be sure you've followed [these steps](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line) first to make the `code` command available. > If on a Mac, be sure you've followed [these steps](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line) first to make the `code` command available.
### 3. Run the "inner loop" build ### 3. Run the "inner loop" build
Now that we have VS Code open with the bootcamp code, open the terminal again `ctrl + ~` and your project should look like this At this point, your VS Code window should look something like this:
<img src="https://user-images.githubusercontent.com/1434956/53654442-9c379400-3c02-11e9-8768-d19e092b606d.png" width=500 /> <img src="https://user-images.githubusercontent.com/1434956/53654442-9c379400-3c02-11e9-8768-d19e092b606d.png" width=500 />
To run the dev "inner loop" for the first 3 lessons type: To start the dev "inner loop," run:
``` ```
npm run static npm start
``` ```
When we get to lesson 4, and React we will stop the static inner loop and start: This will load the site shown below.
1. press `ctrl + c` to stop the static inner loop
```
npm run start
```
Both of these above commands will load the following site:
<img src="https://user-images.githubusercontent.com/1434956/53656239-88426100-3c07-11e9-8456-e3d958aa4def.png" width=500 /> <img src="https://user-images.githubusercontent.com/1434956/53656239-88426100-3c07-11e9-8456-e3d958aa4def.png" width=500 />
## What to Expect ## What to expect
For each lesson, the presenter will walk through some demo code to teach core concepts about the topic. Don't worry about writing code at this point. Just follow along via the readmes linked below.
Most lessons also have an exercise portion. Exercise instructions are usually found in the readme for each step's "exercise" folder.
### Day one ### Day one
Day one is going to cover the basics of HTML, CSS and JavaScript, as well as an introduction to React and Typescript. Day one covers the basics of HTML, CSS and JavaScript, as well as an introduction to React and Typescript.
#### How we'll work
The format of this day is the following:
1. I will walk through some demo code to teach some core concepts about the topic. Don't worry about writing code at this point. Just follow along via the readme's listed below.
2. In the excercise portion return to VS Code and open the 'exercise' folder for the given exercise. The demo folder will include a README file with directions and a link to the demo page.
#### Course Material
1. [Introduction to HTML, CSS and JavaScript](step1-01)
2. [Writing a Todo App: HTML and CSS](step1-02)
3. [Writing a Todo App: JavaScript](step1-03)
4. [React Introduction](step1-04)
5. [Building a Static Page](step1-05)
6. [State Driven UI](step1-06)
7. [Types & UI Driven State](step1-07)
1. [Introduction to HTML](step1-01)
2. [Introduction to CSS](step1-02)
3. [Introduction JavaScript](step1-03)
4. [Introduction to React](step1-04)
5. [Building a static page](step1-05)
6. [State-driven UI](step1-06)
7. [Types and UI-driven state](step1-07)
### Day two ### Day two
The demos and exercises for today are combined. 1. [TypeScript basics](step2-01)
2. [UI Fabric component library](step2-02)
3. [Theming and styling](step2-03)
4. [React Context](step2-04)
5. [Redux: Store](step2-05)
6. [Redux: React binding](step2-06)
1. [Introduction to TypeScript](step2-01) ### Bonus content
2. [UI Fabric Component Library](step2-02)
3. [Theming and Styling](step2-03)
4. [Testing with Jest](step2-04)
5. [Redux: Reducers](step2-05)
6. [Redux: Dispatching Actions and Examining State](step2-06)
7. [Redux: Stores and Dispatch](step2-07)
8. [Redux: Combining Reducers](step2-08)
9. [Redux: Thunk Middleware](step2-09)
### Additional resources * [Redux: Service calls](bonus-servicecalls)
* [Testing with Jest](bonus-jest)
## Additional resources
- [MDN Web Docs](https://developer.mozilla.org/en-US/) - [MDN Web Docs](https://developer.mozilla.org/en-US/)
- [React Docs](https://reactjs.org/docs/getting-started.html) - [React Docs](https://reactjs.org/docs/getting-started.html)
- [Thinking in React](https://reactjs.org/docs/thinking-in-react.html) - [Thinking in React](https://reactjs.org/docs/thinking-in-react.html)
### Follow the authors! ## Follow the authors!
If you are interested in JavaScript, TypeScript, React, Redux, or Design Systems, follow us on Twitter: If you are interested in JavaScript, TypeScript, React, Redux, or Design Systems, follow us on Twitter:
- [@kenneth_chau](https://twitter.com/kenneth_chau) - [@kenneth_chau](https://twitter.com/kenneth_chau)
- [@micahgodbolt](https://twitter.com/micahgodbolt) - [@micahgodbolt](https://twitter.com/micahgodbolt)
### Other projects from the UI Fabric team at Microsoft ## Other projects from the UI Fabric team at Microsoft
- [UI Fabric](https://developer.microsoft.com/en-us/fabric) - [github repo](https://github.com/officedev/office-ui-fabric-react) - [UI Fabric](https://developer.microsoft.com/en-us/fabric) - [github repo](https://github.com/officedev/office-ui-fabric-react)
- [Just](https://microsoft.github.io/just): The task library that just works - [github repo](https://github.com/Microsoft/just) - [Just](https://microsoft.github.io/just): The task library that just works - [github repo](https://github.com/Microsoft/just)

Просмотреть файл

@ -6,25 +6,25 @@
In this exercise, we will work on implementing simple unit tests using Jest. In this exercise, we will work on implementing simple unit tests using Jest.
## Jest Features ## Jest features
- Multi-threaded and isolated test runner - Multi-threaded and isolated test runner
- Provides a fake browser-like environment if needed (window, document, DOM, etc) using jsdom - Provides a fake browser-like environment if needed (window, document, DOM, etc) using [jsdom](https://github.com/jsdom/jsdom)
- Snapshots: Jest can create text-based snapshots of rendered components. These snapshots can be checked in and show API or large object changes alongside code changes in pull requests. - Snapshots: Jest can create text-based snapshots of rendered components. These snapshots can be checked in and show API or large object changes alongside code changes in pull requests.
- Code coverage is integrated (`--coverage`) - Code coverage is integrated (`--coverage`)
- Very clear error messages showing where a test failure occurred - Very clear error messages showing where a test failure occurred
## How to use Jest ## How to use Jest
- Using `create-react-app` or other project generators, Jest should already be pre-configured. Running `npm test` usually will trigger it! Using `create-react-app` or other project generators, Jest should already be pre-configured. Running `npm test` usually will trigger it!
- A `jest.config.js` file is used for configuration
- `jsdom` might not have enough API from real browsers, for those cases, polyfills are required. Place these inside `jest.setup.js` and hook up the setup file in `jest.config.js` Setting up Jest in a new project is outside the scope of this course, but if you're interested in how it works, take a look at the bootcamp project's `jest.config.js` and `jest.setup.js` files or the [getting started documentation](https://jestjs.io/docs/en/getting-started).
- in order to use `enzyme` library to test React Components, more config bits are needed inside `jest.setup.js`
## What does a test look like? ## What does a test look like?
```ts ```ts
// describe(), it() and expect() are globally exported, so they don't need to be imported when jest runs these tests // describe(), it() and expect() are globally exported,
// so they don't need to be imported in each test file
describe('Something to be tested', () => { describe('Something to be tested', () => {
it('should describe the behavior', () => { it('should describe the behavior', () => {
expect(true).toBe(true); expect(true).toBe(true);
@ -32,6 +32,12 @@ describe('Something to be tested', () => {
}); });
``` ```
- `describe()` takes a string describing the thing to be tested (often a component or file name) and a function which runs tests.
- `it()` takes a string describing the behavior to be tested and a function to run the test.
- `expect()` takes the actual value as a parameter and returns an object with various "matcher" methods to test against an expected value/condition. `toBe` is just one of [many available matchers](https://jestjs.io/docs/en/expect).
> When choosing test names, think of the strings passed to `describe` and `it` as forming a sentence. For example, inside `describe('MyComponent', ...)` you might have a test `it('renders some text', ...)`, which forms the sentence a sentence describing the behavior: "MyComponent renders some text."
## Testing React components using Enzyme ## Testing React components using Enzyme
[Enzyme](https://airbnb.io/enzyme/) is made by Airbnb and provides utilities to help test React components. [Enzyme](https://airbnb.io/enzyme/) is made by Airbnb and provides utilities to help test React components.
@ -88,7 +94,7 @@ it('some test function', () => {
Read more about jest mocking [here](https://jestjs.io/docs/en/mock-functions.html). Read more about jest mocking [here](https://jestjs.io/docs/en/mock-functions.html).
### Async Testing ### Async testing
For testing async scenarios, the test runner needs some way to know when the scenario is finished. Jest tests can handle async scenarios using callbacks, promises, or async/await. For testing async scenarios, the test runner needs some way to know when the scenario is finished. Jest tests can handle async scenarios using callbacks, promises, or async/await.

Просмотреть файл

@ -145,7 +145,7 @@
</li> </li>
<li class="Tile Tile--numbered"> <li class="Tile Tile--numbered">
<div class="Tile-link"> <div class="Tile-link">
jest: testing code Testing with Jest
<div class="Tile-links"> <div class="Tile-links">
<a target="_blank" href="./bonus-jest/demo/">demo</a> | <a target="_blank" href="./bonus-jest/exercise/">exercise</a> <a target="_blank" href="./bonus-jest/demo/">demo</a> | <a target="_blank" href="./bonus-jest/exercise/">exercise</a>
</div> </div>

Просмотреть файл

@ -1,4 +1,6 @@
# How the Web Works # Step 1.1 - Introduction to HTML (Demo)
## How the web works
A simple web page is rendered on the screen via the following steps. A simple web page is rendered on the screen via the following steps.
@ -21,7 +23,7 @@ A simple web page is rendered on the screen via the following steps.
![MDN Page Load](https://user-images.githubusercontent.com/1434956/53033758-9da8d580-3426-11e9-9ab8-09f42ccab9a8.png) ![MDN Page Load](https://user-images.githubusercontent.com/1434956/53033758-9da8d580-3426-11e9-9ab8-09f42ccab9a8.png)
# HTML Demo ## HTML demo
HTML tags are the basis of all web applications. They give the page structure and define the content within. HTML tags are the basis of all web applications. They give the page structure and define the content within.
@ -35,7 +37,7 @@ HTML tags can also be nested to create a tree that we call the [Document Object
The [HTML demo page](https://microsoft.github.io/frontend-bootcamp/step1-01/demo) shows a large collection of HTML elements that you will come across during development. The full list of elements can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element). The [HTML demo page](https://microsoft.github.io/frontend-bootcamp/step1-01/demo) shows a large collection of HTML elements that you will come across during development. The full list of elements can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element).
## Sample Website ## Sample webpage
```html ```html
<html> <html>

Просмотреть файл

@ -1 +1,3 @@
Readme is in index.html # Step 1.1 - Introduction to HTML (Exercise)
See index.html from [npm start](http://localhost:8080/step1-01/exercise/) or the [live site](https://microsoft.github.io/frontend-bootcamp/step1-01/exercise/) for the exercise.

Просмотреть файл

@ -1,6 +1,6 @@
## CSS Demo # Step 1.2 - Introduction to CSS (Demo)
### CSS Properties ## CSS properties
Now that we've gone over adding HTML tags to the page, let's cover adding styles to those tags. We can do quite a lot with styles! We can change: Now that we've gone over adding HTML tags to the page, let's cover adding styles to those tags. We can do quite a lot with styles! We can change:
@ -15,7 +15,7 @@ Now that we've gone over adding HTML tags to the page, let's cover adding styles
CSS styles are always written in `property: value` pairs (like `background: blue;`) and terminated with a semicolon. CSS styles are always written in `property: value` pairs (like `background: blue;`) and terminated with a semicolon.
### Applying CSS to an HTML file ## Applying CSS to an HTML file
CSS can be applied to HTML tags in three different ways. CSS can be applied to HTML tags in three different ways.
@ -25,7 +25,7 @@ CSS can be applied to HTML tags in three different ways.
3. Through an external CSS file 3. Through an external CSS file
- `<link rel="stylesheet" href="./css-demo-finished.css" />` - `<link rel="stylesheet" href="./css-demo-finished.css" />`
### Targeting specific elements ## Targeting specific elements
Inline styles are always applied directly to the element you place them on, but `<style>` tags and external CSS files need a way to match elements with their respective style sets. This is done with **[CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors)**. When selectors are combined with CSS styles, we call this a **ruleset**. Inline styles are always applied directly to the element you place them on, but `<style>` tags and external CSS files need a way to match elements with their respective style sets. This is done with **[CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors)**. When selectors are combined with CSS styles, we call this a **ruleset**.

Просмотреть файл

@ -0,0 +1,3 @@
# Step 1.2 - Introduction to CSS (Exercise)
See index.html from [npm start](http://localhost:8080/step1-02/exercise/) or the [live site](https://microsoft.github.io/frontend-bootcamp/step1-02/exercise/) for the exercise.

Просмотреть файл

@ -10,22 +10,22 @@
data-default-tab="html,result" data-default-tab="html,result"
> >
<pre data-lang="css"> <pre data-lang="css">
/* 1. */ /* 1. */
/* 2. */ /* 2. */
/* 3. */ /* 3. */
/* 4. */ /* 4. */
/* 5. */ /* 5. */
/* 6. */ /* 6. */
/* Bonus */ /* Bonus */
</pre> </pre>
<pre data-lang="html"> <pre data-lang="html">
&lt;!-- Without changing the below markup apply the styles asked for in the markup. Do not apply styles that a tag doesn't ask for --> &lt;!-- Without changing the HTML markup, apply the styles asked for in the markup. Do not apply styles that a tag doesn't ask for. -->
&lt;section&gt; &lt;section&gt;
&lt;h2&gt;1. Text Color: Red&lt;/h2&gt; &lt;h2&gt;1. Text Color: Red&lt;/h2&gt;
@ -38,7 +38,7 @@
&lt;/ul&gt; &lt;/ul&gt;
&lt;div class=&quot;myClass&quot;&gt;4. Background Green&lt;/div&gt; &lt;div class=&quot;myClass&quot;&gt;4. Background Green&lt;/div&gt;
&lt;div class=&quot;myClass otherClass&quot;&gt; &lt;div class=&quot;myClass otherClass&quot;&gt;
5. Background Green &amp; Color White 5. Background Green &amp; Color White
(Hint Qualified Selector) (Hint Qualified Selector)
&lt;/div&gt; &lt;/div&gt;
&lt;div id=&quot;myId&quot; class=&quot;otherClass&quot;&gt;6. Background Yellow&lt;/div&gt; &lt;div id=&quot;myId&quot; class=&quot;otherClass&quot;&gt;6. Background Yellow&lt;/div&gt;

Просмотреть файл

@ -1,4 +1,4 @@
# JavaScript Demo # Step 1.3 - Introduction to JavaScript (Demo)
It's entirely possible to create a website with nothing but HTML and CSS, but as soon as you want user interaction other than links and forms, you'll need to reach for JavaScript, the scripting language of the web. Fortunately, JavaScript has grown up quite a bit since it was introduced in the '90s, and now runs just about everything: web applications, mobile applications, native applications, servers, robots and rocket ships. It's entirely possible to create a website with nothing but HTML and CSS, but as soon as you want user interaction other than links and forms, you'll need to reach for JavaScript, the scripting language of the web. Fortunately, JavaScript has grown up quite a bit since it was introduced in the '90s, and now runs just about everything: web applications, mobile applications, native applications, servers, robots and rocket ships.
@ -20,7 +20,7 @@ By the end of the demo we'll have covered the following:
- Loops - Loops
- Interacting with the DOM (Document Object Model) - Interacting with the DOM (Document Object Model)
## Introduction To Variables ## Introduction to variables
We can create a new variable with the keywords `var`, `let`, `const` and use them within our application. These variables can contain one of the following types of values: We can create a new variable with the keywords `var`, `let`, `const` and use them within our application. These variables can contain one of the following types of values:
@ -35,7 +35,7 @@ We can create a new variable with the keywords `var`, `let`, `const` and use the
> [When to use `var`/`let`/`const`?](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable-in-jav) Use `const` for variables you never expect to change, and `let` for anything else. `var` is mostly no longer used. See the link for more details about how each works. > [When to use `var`/`let`/`const`?](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable-in-jav) Use `const` for variables you never expect to change, and `let` for anything else. `var` is mostly no longer used. See the link for more details about how each works.
### Variable Examples ### Variable examples
```js ```js
const myBoolean = true; const myBoolean = true;
@ -50,7 +50,7 @@ const myFunction = function(myNumberParam) {
> JavaScript is a dynamically typed language, so if you initially store a number in a variable (`let myVar = 0`), you can change it to contain a string by simply writing `myVar = 'hello'` without any trouble. > JavaScript is a dynamically typed language, so if you initially store a number in a variable (`let myVar = 0`), you can change it to contain a string by simply writing `myVar = 'hello'` without any trouble.
### Adding Variables ### Adding variables
Let's start off our demo by adding a variable to our [script tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script). This variable will be global and constant. Let's start off our demo by adding a variable to our [script tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script). This variable will be global and constant.
@ -76,7 +76,7 @@ Functions on their own don't have any effect on the page. When I declare `functi
To execute a function we need to attach it to an event. There are a number of possible events: keyboard strokes, mouse clicks, document loading, and more. To execute a function we need to attach it to an event. There are a number of possible events: keyboard strokes, mouse clicks, document loading, and more.
### Add Event Listeners ### Add event listeners
To attach a function to an event, we use an [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventListener) like this: To attach a function to an event, we use an [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventListener) like this:
@ -92,7 +92,7 @@ window.addEventListener('click', function() {
> [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) is a reference to the entire window containing the HTML document. > [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) is a reference to the entire window containing the HTML document.
### Global Event Handlers ### Global event handlers
If you think this feels a little verbose, you're not alone. Many of the [most common event types](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers) are available as element properties. This way we can set properties like `onload` or `onclick` like this: If you think this feels a little verbose, you're not alone. Many of the [most common event types](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers) are available as element properties. This way we can set properties like `onload` or `onclick` like this:
@ -208,7 +208,3 @@ function displayMatches() {
document.querySelector('.submit').value = matches + ' matches'; document.querySelector('.submit').value = matches + ' matches';
} }
``` ```
## Next Step
[Start our Todo App](../../step1-02/demo/)

Просмотреть файл

@ -1,11 +1,3 @@
# Exercise # Step 1.3 - Introduction to JavaScript (Exercise)
1. Create a function named `getFavs`. Inside, run `alert('clicked')`. See index.html from [npm start](http://localhost:8080/step1-03/exercise/) or the [live site](https://microsoft.github.io/frontend-bootcamp/step1-03/exercise/) for the exercise.
2. Create a variable `button` and set it to a reference to our button by using `document.querySelector('button')`
3. Add a click event listener to the button that calls `getFavs`. Click the button and make sure the alert is displayed.
4. Replace the `alert` call with a new `favList` variable set to an empty array: `[]`
5. Create a const variable `inputs` set to all of the inputs on the page. [`querySelectorAll`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) will help here.
6. Iterate over all of the inputs using `for (const input of inputs) {}`
7. In each iteration, use an `if` statement to check if `input.checked` is equal to true
8. If the above tests passes, push the `input.parentNode.textContent` onto the `favList` array by passing the text as a parameter to `favList.push()` ([`push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) is a built-in array method.)
9. Outside of the for loop, use `document.querySelector('.favorites')` to target the div at the bottom of the page. Set the div's `textContent` to `favList.join(' ')`. This will join each of the foods together into a string separated by a space.

Просмотреть файл

@ -28,16 +28,33 @@ button {
&lt;div class=&quot;favorites&quot;&gt;&lt;/div&gt; &lt;div class=&quot;favorites&quot;&gt;&lt;/div&gt;
</pre> </pre>
<pre data-lang="js"> <pre data-lang="js">
/* /*
1. Create a function named `getFavs` and set its contents to `alert('clicked')` 1. Create a function named `getFavs`. Inside, run:
2. Create a variable `button` and set it to a reference to our button by using `document.querySelector('button')` alert('clicked')
3. Add a click event listener to the button that calls `getFavs`. Click the button and make sure it calls our alert.
4. Replace the alert with a new `favList` variable set to an empty array: `[]` 2. Create a variable `button` and set it to a reference to our button using:
5. Create a const variable `inputs` set to all of the inputs on the page. `querySelectorAll` will help here document.querySelector('button')
6. Iterate over all of the inputs using `for (const input of inputs) {}`
7. For each iteration use an `if` statement to check if `input.checked` is equal to true 3. Add a click event listener to the button that calls `getFavs`.
8. If the above tests passes, push the `input.parentNode.textContent` onto the `favList` array. Pass that text into `favList.push()` as the parameter to add it to the array Click the button and make sure the alert is displayed.
9. Outside of the for loop, use `document.querySelector('.favorites')` to target the div at the bottom of the page. Set the div's `textContent` to `favList.join(' ')`. This will join each of the foods together into a string separated by a space.
4. Replace the `alert` call with a new `favList` variable set to an empty array: []
5. Create a const variable `inputs` set to all of the inputs on the page.
`querySelectorAll` will help here.
6. Iterate over all of the inputs using:
for (const input of inputs) {}
7. In each iteration, use an `if` statement to check if `input.checked` is equal to true
8. If the above tests passes, push the `input.parentNode.textContent` into the `favList`
array by passing the text as a parameter to `favList.push()`
- `push` is a built-in array method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
9. Outside of the for loop, use `document.querySelector('.favorites')` to target the
div at the bottom of the page. Set the div's `textContent` to `favList.join(' ')`.
This will join each of the foods together into a string separated by a space.
*/ */
</pre> </pre>

Просмотреть файл

@ -1,4 +1,4 @@
# Step 4 - Introduction To React Demo # Step 1.4 - Introduction to React (Demo)
In this demo we'll be creating a simple counter that will display a count and increment on click. In this demo we'll be creating a simple counter that will display a count and increment on click.
@ -19,7 +19,7 @@ The first parameter to `render()` looks a lot like HTML, but actually, it's [JSX
- Controls can be self-closing: `<MyControl text='hi' />` - Controls can be self-closing: `<MyControl text='hi' />`
- You can use JavaScript inside of JSX! - You can use JavaScript inside of JSX!
## Writing a React Component ## Writing a React component
A React component is a piece of code that returns a portion of your application. This can include HTML markup, CSS styles, and JavaScript driven functionality. A React component is a piece of code that returns a portion of your application. This can include HTML markup, CSS styles, and JavaScript driven functionality.
@ -87,7 +87,7 @@ const App = props => {
}; };
``` ```
### Destructuring Props ### Destructuring props
Writing `props.text` over and over in a function (or `this.props.text` in a class) can be quite tedious. Since this is all JavaScript, you could create a new variable for this text using variable assignment. Writing `props.text` over and over in a function (or `this.props.text` in a class) can be quite tedious. Since this is all JavaScript, you could create a new variable for this text using variable assignment.
@ -159,13 +159,13 @@ ReactDOM.render(<App />, document.getElementById('app'));
> Note the capitalization of `Counter`. HTML might not be case-sensitive, but JSX is! A common practice is to use the capitalized names of HTML elements to name corresponding React components: Button, Select, Label, Form, etc. > Note the capitalization of `Counter`. HTML might not be case-sensitive, but JSX is! A common practice is to use the capitalized names of HTML elements to name corresponding React components: Button, Select, Label, Form, etc.
## React State ## Writing a stateful Counter component
React allows each control to specify its own data store, called **state**. We can reference values in state when we render our UI, and we can also update state over the lifetime of our application. React allows each control to specify its own data store, called **state**. We can reference values in state when we render our UI, and we can also update state over the lifetime of our application.
> Most stateful components you'll see today will be `class` based. It is just recently possible to add state to function components through the use of [`hooks`](https://reactjs.org/docs/hooks-intro.html) > Most stateful components you'll see today will be `class` based. It is just recently possible to add state to function components through the use of [`hooks`](https://reactjs.org/docs/hooks-intro.html)
### Adding State ### Adding state
JavaScript classes use a `constructor` method to instantiate each copy of a class, along with any applicable state. Let's create a new component called `Counter` and give it a state containing a `clicks` property with a default value of `0`; JavaScript classes use a `constructor` method to instantiate each copy of a class, along with any applicable state. Let's create a new component called `Counter` and give it a state containing a `clicks` property with a default value of `0`;
@ -184,7 +184,7 @@ class Counter extends React.Component {
- The [`super()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) function calls the constructor of the parent class (in this case `React.Component`). - The [`super()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) function calls the constructor of the parent class (in this case `React.Component`).
- Our `counter` state value can now be accessed via `this.state.counter`. Later, we can update state by calling `this.setState({ counter: 1 })`. - Our `counter` state value can now be accessed via `this.state.counter`. Later, we can update state by calling `this.setState({ counter: 1 })`.
### Creating our Counter ### Rendering our Counter
For our `Counter` component, the goal is to be able to track how many times the counter's button is clicked. We'll use the following markup. For our `Counter` component, the goal is to be able to track how many times the counter's button is clicked. We'll use the following markup.
@ -201,7 +201,7 @@ render() {
} }
``` ```
### Writing our Button Click Handler ### Writing our button click handler
Our next step is to wire up the button to increment the `counter` in our component state. Our next step is to wire up the button to increment the `counter` in our component state.
@ -235,11 +235,11 @@ Add a couple `Counter`s to our `App`, each with different text. Notice how they
## Moving this into our codebase ## Moving this into our codebase
To scale our application we'll need to break up the file into smaller, reusable pieces. In this part of the demo we'll look at the `final` folder and how the JavaScript module system allows us to break up our components into a collection of files exporting their functionality. To scale our application, we'll need to break up the file into smaller, reusable pieces. In this part of the demo we'll look at the `final` folder and how the JavaScript module system allows us to break up our components into a collection of files exporting their functionality.
### Module Exports and Imports ### Module exports and imports
Open up the `step1-04/final/components/Counter.tsx` and look at the `Counter` component. Open up `step1-04/final/components/Counter.tsx` and look at the `Counter` component.
```tsx ```tsx
export class Counter extends React.Component { export class Counter extends React.Component {
@ -255,7 +255,7 @@ import { Counter } from './components/Counter';
> Note the `{}` wrapped around the import value. This is actually an example of destructuring. > Note the `{}` wrapped around the import value. This is actually an example of destructuring.
#### Default Exports #### Default exports
We typically use named exports, but it's also possible export a default value like this: We typically use named exports, but it's also possible export a default value like this:
@ -271,7 +271,7 @@ When we import the component we can call it whatever we want:
import SomeCounterComponent from './components/Counter'; import SomeCounterComponent from './components/Counter';
``` ```
## Using a Button component ## Writing a Button component
Buttons are among the most commonly written components. Custom buttons help abstract common styling, add icons or other decorations, and increase functionality (menu buttons etc). Let's take a quick look at a custom button component to see how it comes together. Buttons are among the most commonly written components. Custom buttons help abstract common styling, add icons or other decorations, and increase functionality (menu buttons etc). Let's take a quick look at a custom button component to see how it comes together.

3
step1-04/final/README.md Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Step 1.4 - Introduction to React (Final)
Take a look at the contents of the `src` folder to see final versions of the `App`, `Button`, and `Counter` components from this lesson.

Просмотреть файл

@ -2,7 +2,7 @@
<html> <html>
<body> <body>
<header> <header>
<h1>todos</h1> <h1>todos <small>(1.5)</small></h1>
<div class="addTodo"> <div class="addTodo">
<input class="textfield" placeholder="add todo" /> <input class="textfield" placeholder="add todo" />
<button class="submit">Add</button> <button class="submit">Add</button>

Просмотреть файл

@ -1,19 +1,19 @@
# Step 1-05: Demo Building a Static Page # Step 1.5 - Building a static page in React (Demo)
To start off our todo application we are going to follow the steps outlined in [Thinking in React](https://reactjs.org/docs/thinking-in-react.html). The first step of the process is to break our application into a component hierarchy. For this app, we're going to keep it simple and just use four parts. To start building our todo application, we'll follow the steps outlined in [Thinking in React](https://reactjs.org/docs/thinking-in-react.html). The first step of the process is to break our application into a component hierarchy. For this app, we're going to keep it simple and just use four parts.
- TodoHeader - TodoHeader
- TodoList - TodoList
- TodoListItem - TodoListItem
- TodoFooter - TodoFooter
You can find the HTML for our application in `step1-05/TodoApp.html` You can find the HTML for our application in `step1-05/TodoApp.html`.
## TodoHeader ## TodoHeader
We are going to store all of our components inside of a `components` folder. Lets create that now. We'll then start with the `TodoHeader` inside of a file called `TodoHeader.tsx`. This file format tells our application that this file includes React code written in Typescript. We'll store all of our components inside a `components` folder under `src`. Let's create that now. We'll then start writing the `TodoHeader` in `components/src/TodoHeader.tsx`. The `tsx` file extension tells our editor that this file includes React code written in TypeScript.
> We'll talk about Typescript soon, but for now know that all valid JavaScript is valid Typescript > We'll talk about TypeScript soon, but for now, know that all valid JavaScript is valid TypeScript.
```jsx ```jsx
import React from 'react'; import React from 'react';
@ -38,7 +38,7 @@ export class TodoHeader extends React.Component<any, any> {
} }
``` ```
> Note that since this is React we had to change `class` to `className`, but nothing else changes. > Note that since this is React, we had to change `class` to `className`, but nothing else changes.
## TodoListItem ## TodoListItem
@ -60,4 +60,15 @@ export class TodolistItem extends React.Component<any, any> {
} }
``` ```
> Note that this control could also be created as a function instead of a class: `export const TodoListItem = (props) => {}` > Note that this control could also be created as a function instead of a class:
> ```jsx
> export const TodoListItem = (props) => {
> return (
> <li className="todo">
> <label>
> <input type="checkbox" /> Todo 1
> </label>
> </li>
> );
> }
> ```

Просмотреть файл

@ -1,16 +1,20 @@
# Step 1-06 Exercise # Step 1.5 - Building a static page in React (Exercise)
### TodoFooter From this exercise on, we'll be working in VS Code instead of CodePen. If you don't already have the bootcamp folder open in a VS Code window, see the [main readme](https://github.com/Microsoft/frontend-bootcamp/blob/master/README.md) for instructions.
1. Add a TodoFooter component in the `components` folder, copying over the `<footer>` tag and all of its children from `TodoApp.html` in the `step1-05` folder. This could be a function or class. If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 1 step 5 to see results.
## TodoFooter
1. Add a TodoFooter component in the `components` folder, copying over the `<footer>` tag and all of its children from `TodoApp.html` in the `step1-05` folder. This component could be a function or class.
2. Remove any `onclick` properties, and change `class` to `className` 2. Remove any `onclick` properties, and change `class` to `className`
### TodoList ## TodoList
1. Add a TodoList component like you did with the footer. This could also be function or class. 1. Add a TodoList component like you did with the footer. This could also be function or class.
2. Import TodoListItem and add 4 of them inside of the `<ul>` 2. Import TodoListItem and add four of them inside of the `<ul>`
3. Bonus points for using a [`for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration) loop or using [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to create 4 list items based on the array `[1,2,3,4]` 3. Bonus points for using a [`for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration) loop or using [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to create 4 list items based on the array `[1,2,3,4]`
## App.tsx ## App
1. Import both of these components into `App.tsx` and place their tags below the `TodoHeader`. 1. Import both of these components into `App.tsx` and place their tags below the `TodoHeader`.

Просмотреть файл

@ -4,7 +4,7 @@ export class TodoHeader extends React.Component<any, any> {
render() { render() {
return ( return (
<header> <header>
<h1>todos - step1-05 exercise</h1> <h1>todos <small>(1.5 exercise)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input className="textfield" placeholder="add todo" /> <input className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -1,12 +1,12 @@
# Step 1-06 Demo: Creating a State-Driven UI # Step 1.6 - Creating a state-driven UI (Demo)
In React, the data travels in one direction: top-down in the form of state propagating down the component hierarchy. Only the component containing the state can change the state itself. When a UI interaction occurs, a stateful component must pass down an event handler to the UI component triggering the event in order to signal a state change. In React, the data travels in one direction: top-down in the form of state propagating down the component hierarchy. Only the component containing the state can change the state itself. When a UI interaction occurs, a stateful component must pass down an event handler to the UI component triggering the event in order to signal a state change.
[Step #3 of "Thinking in React"](https://reactjs.org/docs/thinking-in-react.html) suggests finding the "minimal set of mutable state" that your application requires. So in this demo we are going to add that "minimal state" to our application and drive our UI off of that data. With that done, the next step will be to create ways to modify that state, which will in turn cascade down through our UI. This [reconciliation](https://reactjs.org/docs/reconciliation.html) process, figuring out what in your UI needs to change based on changing state, is what React excels at. [Step #3 of "Thinking in React"](https://reactjs.org/docs/thinking-in-react.html) suggests finding the "minimal set of mutable state" that your application requires. So in this demo we are going to add that "minimal state" to our application and drive our UI off of that data. With that done, the next step will be to create ways to modify that state, which will in turn cascade down through our UI. This [reconciliation](https://reactjs.org/docs/reconciliation.html) process, figuring out what in your UI needs to change based on changing state, is what React excels at.
## Adding State to `TodoApp.tsx` ## Adding state to TodoApp
Inside our `TodoApp` class, we will add the minimal state for our application, which includes just two keys: `todos` and `filter`. We don't need to worry about a `remaining` value because it can be calculated by counting the number of todos where the `completed` field is set to `false`. Inside our `TodoApp` class, we will add the minimal state for our application, which includes just two keys: `todos` and `filter`. We don't need to worry about a `remaining` count because it can be calculated by counting the number of todos where the `completed` field is set to `false`.
So here is our full constructor: So here is our full constructor:
@ -39,7 +39,7 @@ constructor(props) {
> You could also use an array to represent your todos. Array manipulation can be easier in some cases, but this object approach simplifies other functionality and will ultimately be more performant. > You could also use an array to represent your todos. Array manipulation can be easier in some cases, but this object approach simplifies other functionality and will ultimately be more performant.
## Passing State Through to UI ## Passing state through to UI
Now we can pass `filter` and `todos` into our components. Now we can pass `filter` and `todos` into our components.
@ -56,7 +56,7 @@ render() {
} }
``` ```
## State-Driven TodoList ## State-driven TodoList
I've already pulled out our props into `filter` and `todos` variables, and written a bit of JS that will return an array of filtered todo `id`s. We'll be using that filtered array to render our todo items. I've already pulled out our props into `filter` and `todos` variables, and written a bit of JS that will return an array of filtered todo `id`s. We'll be using that filtered array to render our todo items.
@ -72,11 +72,11 @@ return (
); );
``` ```
## State-Driven and Stateful Header ## State-driven and stateful TodoHeader
Within the header we've got a situation where we not only want to pass `filter` state down to it, but we also want to maintain state within the control. Fortunately, this is no problem at all for React. First off let's deal with the incoming state. Within the header, we've got a situation where we not only want to pass `filter` state down to it, but we also want to maintain state within the control. Fortunately, this is no problem at all for React. First off let's deal with the incoming state.
### Conditional Class Names ### Conditional class names
In CSS-based styling, visual states are applied by adding and removing classes. We can use the filter value to conditionally add a class, thereby lighting up the correct filter button. In CSS-based styling, visual states are applied by adding and removing classes. We can use the filter value to conditionally add a class, thereby lighting up the correct filter button.
@ -90,7 +90,7 @@ In CSS-based styling, visual states are applied by adding and removing classes.
> The [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) `condition ? expressionIfTrue : expressionIfFalse` is widely used in React code, as each expression could be a string for a className or even a JSX element. > The [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) `condition ? expressionIfTrue : expressionIfFalse` is widely used in React code, as each expression could be a string for a className or even a JSX element.
### Adding a Controlled Input ### Adding a controlled input
In React, form elements such as `<input>`, `<textarea>`, and `<select>` can be used as either **uncontrolled** or **controlled**. In React, form elements such as `<input>`, `<textarea>`, and `<select>` can be used as either **uncontrolled** or **controlled**.

Просмотреть файл

@ -10,7 +10,7 @@ export class TodoHeader extends React.Component<any, any> {
const { filter } = this.props; const { filter } = this.props;
return ( return (
<header> <header>
<h1>todos - step1-06 demo</h1> <h1>todos <small>(1.6 demo)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input className="textfield" placeholder="add todo" /> <input className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>

Просмотреть файл

@ -12,7 +12,7 @@ export class TodoList extends React.Component<any, any> {
return ( return (
<ul className="todos"> <ul className="todos">
[01, 02, 03, 04].map((id)=> <TodoListItem />) {['01', '02', '03', '04'].map((id) => <TodoListItem />)}
</ul> </ul>
); );
} }

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -1,11 +1,11 @@
## Exercise # Step 1.6 - Creating a state-driven UI (Exercise)
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 1 step 6 to see results. If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 1 step 6 to see results.
### TodoFooter ### TodoFooter
1. Use the provided `itemCount` value to display the current number of items left. 1. Use the provided `itemCount` value to display the current number of items left.
2. Use a ternary operator to print "item" vs "item**s**" based on whether `itemCount === 1`. 2. Use a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) to print "item" vs "item**s**" based on whether `itemCount === 1`.
### TodoListItem ### TodoListItem

Просмотреть файл

@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
return ( return (
<header> <header>
<h1>todos - step1-06 exercise</h1> <h1>todos <small>(1.6 exercise)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" /> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -1,30 +1,30 @@
# Types and Creating a UI-Driven State # Step 1.7 - Types and creating a UI-driven state (Demo)
Now that we have a UI that is purely driven by the state of our app, we need to add functionality to allow the UI to drive the state. This is often done by creating functions that call `setState` like we saw in the `TodoHeader`. Values from the state are then passed down to the UI as props. Now that we have a UI that is purely driven by the state of our app, we need to add functionality to allow the UI to drive the state. This is often done by creating functions that call `setState` like we saw in the `TodoHeader`. Values from the state are then passed down child components as props.
> We'll be learning in part 2 of this workshop how we can expose these functions without explicitly passing them down via props. > We'll be learning in part 2 of this workshop how we can expose these functions without explicitly passing them down via props.
This is our core "business logic" and handles everything our basic "CRUD" operations: Create, Read, Update, Delete. We don't have time to walk through writing all of those functions, but you can see that they are already provided in the demo's `TodoApp` and passed into our components. This is our core "business logic" and handles our basic "CRUD" operations: Create, Read, Update, Delete. We don't have time to walk through writing all of those functions, but you can see that they are already provided in the demo's `TodoApp` and passed into our components.
## Intro to TypeScript ## Intro to TypeScript
Taking a look at our components in `TodoApp`, you can see that our list of props is not just getting longer, but is getting much more complex! We're passing through functions with various signatures, complex `todos` objects, and filter strings which are always one of three values. Taking a look at our components in `TodoApp`, you can see that our list of props is getting not just longer, but much more complex! We're passing through functions with various signatures, complex `todos` objects, and filter strings which are always one of three values.
As applications grow, it becomes increasing difficult to remember what each function does, or what each todo contains. Also, as JavaScript is a dynamically typed language, if I wanted to change the value of `todos` to an array inside my `TodoList`, JavaScript wouldn't care. But if `TodoListItems` was expecting an object, our application would break. As applications grow, it becomes difficult to remember what each function does or what each todo contains. Also, as JavaScript is a dynamically typed language, if I wanted to change the value of `todos` to an array inside my `TodoList`, JavaScript wouldn't care. But if `TodoListItems` was expecting an object, our application would break.
It for these two reasons that the entire industry is shifting to writing applications that are strongly typed, and many are using TypeScript to accomplish that. For these two reasons, the industry is shifting to writing applications that are strongly typed, and many are using TypeScript to accomplish that.
As [TypeScript's website](https://www.typescriptlang.org/) states: As [TypeScript's website](https://www.typescriptlang.org/) states:
> TypeScript is a superset of JavaScript that compiles to plain JavaScript. > TypeScript is a superset of JavaScript that compiles to plain JavaScript.
If you've ever used [Sass](https://sass-lang.com/) you are familiar with this concept. In the same way that all valid CSS is valid Sass, all valid JavaScript is valid TypeScript. That's why most of these exercises have been written in `ts` and `tsx` files instead of `js` and `jsx` files. If you've used [Sass](https://sass-lang.com/), you're familiar with this concept. In the same way that all valid CSS is valid Sass, all valid JavaScript is valid TypeScript. That's why our exercises have been written in `ts` and `tsx` files instead of `js` and `jsx`.
Let's dive into the demo and see how TypeScript can help us better understand our component props and guard against future regressions. Let's dive in and see how TypeScript can help clarify our component props and guard against future regressions.
# Demo # Demo
Let's start off in the TodoList, as that has the most data flow up and down. There isn't any interactive UI in this component, as we're simply passing `completed` down to each `TodoListItem`, but we can write a props interface for the component to make sure that everything gets passed down properly. Let's start off in the TodoList, as that has the most data flow up and down. There isn't any interactive UI in this component, as we're simply passing `completed` down to each `TodoListItem`, but we can write a props interface to make sure that everything gets passed down properly.
## Writing TodoListProps ## Writing TodoListProps

Просмотреть файл

@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
const { filter } = this.props; const { filter } = this.props;
return ( return (
<header> <header>
<h1>todos - step1-07 demo</h1> <h1>todos <small>(1.7 demo)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" /> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -1,12 +1,15 @@
#Step 1-07: Exercise # Step 1.7 - Types and creating a UI-driven state (Exercise)
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 1 step 7 to see results.
## TodoFooter ## TodoFooter
1. Open TodoFooter and write a TodoFooterProps interface. It should include two values, a `clear` and `todos`. Use this interface in the function props like this: `(props: TodoFooterProps)` 1. Open TodoFooter and write a `TodoFooterProps` interface. It should include two values, a `clear` and `todos`. Use this interface in the function props like this: `(props: TodoFooterProps)`
2. Write an `_onClick` function that calls `props.clear`. 2. Write an `_onClick` function that calls `props.clear`.
> Since TodoFooter is not a class, the `_onClick` function needs to be stored in a const placed before the `return`. - Since TodoFooter is not a class, the `_onClick` function needs to be stored in a const placed before the `return`.
- Remember to use an arrow function to define this click handler.
3. Assign `_onClick` to the button's `onClick` prop. You won't need to use `this` since the component isn't a class. 3. Assign `_onClick` to the button's `onClick` prop. You won't need to use `this` since the component isn't a class.
@ -14,13 +17,14 @@
## TodoHeader ## TodoHeader
1. Open TodoHeader and write TodoHeaderProps which will include `addTodo`, `setFilter` and `filter`. Replace the first `any` in the class declaration with this interface. 1. Open TodoHeader and write `TodoHeaderProps` which will include `addTodo`, `setFilter` and `filter`. Replace the first `any` in the class declaration with this interface.
2. This component also has state. Write TodoHeaderState (there's just one value), and add this where the second `any` was. 2. This component also has state. Write `TodoHeaderState` (there's just one value), and add this where the second `any` was.
3. Add `_onFilter` to each of the filter buttons 3. Add `_onFilter` to each of the filter buttons
> Note that we can't add new parameters to onClick, but we can pull information from the event target! - Note that we can't add new parameters to onClick, but we can pull information from the event target!
- Remember to use an arrow function for this one too
4. Call `_onAdd` from the submit button 4. Call `_onAdd` from the submit button

Просмотреть файл

@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
const { filter } = this.props; const { filter } = this.props;
return ( return (
<header> <header>
<h1>todos - step1-07 exercise</h1> <h1>todos <small>(1.7 exercise)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" /> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button className="submit">Add</button> <button className="submit">Add</button>

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -21,7 +21,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
const { filter, setFilter } = this.props; const { filter, setFilter } = this.props;
return ( return (
<header> <header>
<h1>todos - step1-07 final</h1> <h1>todos <small>(1.7 final)</small></h1>
<div className="addTodo"> <div className="addTodo">
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" /> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
<button onClick={this._onAdd} className="submit"> <button onClick={this._onAdd} className="submit">

Просмотреть файл

@ -8,6 +8,10 @@ h1 {
text-align: center; text-align: center;
} }
small {
font-size: 0.5em;
}
.addTodo { .addTodo {
display: flex; display: flex;
} }

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.1: Introduction to TypeScript (Demo) # Step 2.1 - Introduction to TypeScript (Demo)
[Lessons](../../) | [Exercise](../exercise/) [Lessons](../../) | [Exercise](../exercise/)
@ -28,11 +28,11 @@ The most important ones to know about are:
> For more information about the _many_ modularity patterns and standards developed over time, see [this article](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc). You may still encounter some of the older patterns in legacy code. > For more information about the _many_ modularity patterns and standards developed over time, see [this article](https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc). You may still encounter some of the older patterns in legacy code.
## TypeScript Types ## TypeScript types
Refer to [`demo/src/types`](./src/types/index.ts) for examples of some of the types available in TS that benefit a React developer. Refer to [`demo/src/types`](./src/types/index.ts) for examples of some of the types available in TS that benefit a React developer.
## Spread Operator ## Spread operator
The spread operator `...` provides a quick way to clone and concatenate objects and arrays. This syntax is seen a lot inside React props and Redux reducers. The spread operator `...` provides a quick way to clone and concatenate objects and arrays. This syntax is seen a lot inside React props and Redux reducers.
@ -139,7 +139,7 @@ aPromise
> For more information, see [this overview of promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) or [this deep dive](https://developers.google.com/web/fundamentals/primers/promises). > For more information, see [this overview of promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) or [this deep dive](https://developers.google.com/web/fundamentals/primers/promises).
## Async / Await ## Async / await
**Async / Await** is a language-level feature for writing asynchronous functions as if they are ordinary, synchronous code. JS support for this is built on top of `Promise`s and is inspired heavily by [C#'s async / await syntax](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). An async function is written like this: **Async / Await** is a language-level feature for writing asynchronous functions as if they are ordinary, synchronous code. JS support for this is built on top of `Promise`s and is inspired heavily by [C#'s async / await syntax](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). An async function is written like this:

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.1: Introduction to TypeScript (Exercise) # Step 2.1 - Introduction to TypeScript (Exercise)
[Lessons](../../) | [Demo](../demo/) [Lessons](../../) | [Demo](../demo/)
@ -20,7 +20,7 @@ Exercises will be completed under this step's `exercise/src` folder unless other
5. Inside `index.ts` in the same folder, import both `fib` and `FibConst`, and use the built-in `console.log()` function to log the result of `fib(FibConst)`. 5. Inside `index.ts` in the same folder, import both `fib` and `FibConst`, and use the built-in `console.log()` function to log the result of `fib(FibConst)`.
## Types and Interfaces ## Types and interfaces
Inside `exercise/src/index.ts`: Inside `exercise/src/index.ts`:
@ -38,7 +38,7 @@ Inside `exercise/src/stack.ts`, create a generic class for a `Stack<T>` complete
In `exercise/src/index.ts`, create a `Stack<number>` and use `console.log()` to demonstrate its functionality. In `exercise/src/index.ts`, create a `Stack<number>` and use `console.log()` to demonstrate its functionality.
## Spread and Destructuring ## Spread and destructuring
1. Note the following code in index.ts: 1. Note the following code in index.ts:
@ -61,7 +61,7 @@ const obj2 = {
3. Use the destructuring syntax to retrieve the values for `{first, second, catcher}` from `megaObj`. 3. Use the destructuring syntax to retrieve the values for `{first, second, catcher}` from `megaObj`.
## Async / Await ## Async / await
Note the following code in index.ts: Note the following code in index.ts:

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.2: UI Fabric Component Library (Demo) # Step 2.2 - UI Fabric component library (Demo)
[Lessons](../../) | [Exercise](../exercise/) [Lessons](../../) | [Exercise](../exercise/)
@ -11,7 +11,7 @@ We'll talk about:
- [How to use it](#how-to-use-it) - [How to use it](#how-to-use-it)
- [Laying out apps with Stack](#layout-with-stack) - [Laying out apps with Stack](#layout-with-stack)
## What Makes It Good ## What makes it good
- Fabric has been developed BOTH by developers and design engineers working together as a team - Fabric has been developed BOTH by developers and design engineers working together as a team
- Most notable Microsoft web products use it - Most notable Microsoft web products use it
@ -23,7 +23,7 @@ We'll talk about:
- Engineering is done in the open on GitHub - Engineering is done in the open on GitHub
- Engineering system is shared and re-usable by other teams - Engineering system is shared and re-usable by other teams
## How to Find It ## How to find it
GitHub repo: GitHub repo:
https://github.com/officedev/office-ui-fabric-react https://github.com/officedev/office-ui-fabric-react
@ -31,9 +31,9 @@ https://github.com/officedev/office-ui-fabric-react
Documentation: Documentation:
https://developer.microsoft.com/en-us/fabric/#/components https://developer.microsoft.com/en-us/fabric/#/components
## How to Use It ## How to use it
### Importing a Component ### Importing a component
```jsx ```jsx
import { DefaultButton } from 'office-ui-fabric-react'; import { DefaultButton } from 'office-ui-fabric-react';
@ -47,7 +47,7 @@ const MyComponent = () => {
}; };
``` ```
### Customizing Behavior of Individual Components ### Customizing behavior of individual components
Take a look at the [Button documentation](https://developer.microsoft.com/en-us/fabric#/components/button). Take a look at the [Button documentation](https://developer.microsoft.com/en-us/fabric#/components/button).
@ -65,7 +65,7 @@ const MyComponent = () => {
}; };
``` ```
### Customizing Component Rendering ### Customizing component rendering
Some Fabric components take in a render functions to allow customizing certain parts of the component. An example with TextField: Some Fabric components take in a render functions to allow customizing certain parts of the component. An example with TextField:
@ -84,7 +84,7 @@ const MyComponent = () => {
## Layout with Stack ## Layout with Stack
Before we start, let's look at flexbox--a new CSS layout method which is powerful, but really, really complex to use: Before we start, let's look at flexbox--a modern CSS layout method which is powerful, but really, really complex to use:
- A guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/ - A guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
- A tool: http://the-echoplex.net/flexyboxes/ - A tool: http://the-echoplex.net/flexyboxes/

Просмотреть файл

@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
return ( return (
<Stack> <Stack>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos - step2-02 demo</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.2 demo)</Text></Text>
</Stack> </Stack>
<Stack horizontal> <Stack horizontal>

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.2: UI Fabric Component Library (Exercise) # Step 2.2 - UI Fabric component library (Exercise)
[Lessons](../../) | [Demo](../demo/) [Lessons](../../) | [Demo](../demo/)

Просмотреть файл

@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
return ( return (
<Stack> <Stack>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos - step2-02 demo</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.2 exercise)</Text></Text>
</Stack> </Stack>
<Stack horizontal> <Stack horizontal>

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.3: Theming and styling with UI Fabric (Demo) # Step 2.3 - Theming and styling with UI Fabric (Demo)
[Lessons](../../) | [Exercise](../exercise/) [Lessons](../../) | [Exercise](../exercise/)

Просмотреть файл

@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.3 demo)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -1,12 +1,10 @@
# Step 2.3: Theming and styling with UI Fabric (Exercise) # Step 2.3 - Theming and styling with UI Fabric (Exercise)
[Lessons](../../) | [Demo](../demo/) [Lessons](../../) | [Demo](../demo/)
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 3 to see results. If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 3 to see results.
## Fabric theming and styling ## Applying Fabric themes
### Applying Fabric themes
Try applying some predefined themes from UI Fabric packages inside the TodoApp under `exercise/src/components/TodoApp.tsx`. Do this by replacing: Try applying some predefined themes from UI Fabric packages inside the TodoApp under `exercise/src/components/TodoApp.tsx`. Do this by replacing:
@ -20,7 +18,7 @@ with:
import { TeamsCustomizations } from '@uifabric/theme-samples'; import { TeamsCustomizations } from '@uifabric/theme-samples';
``` ```
### Applying customized themes ## Applying customized themes
1. Create your own theme using the [theme generator](https://developer.microsoft.com/en-us/fabric#/styles/themegenerator) and copy the generated code. 1. Create your own theme using the [theme generator](https://developer.microsoft.com/en-us/fabric#/styles/themegenerator) and copy the generated code.
@ -30,7 +28,7 @@ import { TeamsCustomizations } from '@uifabric/theme-samples';
4. Play around with the values and use VS Code's intellisense to discover more properties of the `ITheme` type. 4. Play around with the values and use VS Code's intellisense to discover more properties of the `ITheme` type.
### Customizing one Fabric control instance ## Customizing one Fabric control instance
1. Open `exercise/src/components/TodoFooter.tsx` 1. Open `exercise/src/components/TodoFooter.tsx`
@ -40,9 +38,9 @@ import { TeamsCustomizations } from '@uifabric/theme-samples';
4. Try to customize this with a styles function 4. Try to customize this with a styles function
## Advanced/non-Fabric component styling ## CSS-in-JS with `mergeStyles`
### CSS-in-JS with `mergeStyles` As mentioned in the demo, this is an advanced approach which also works outside of Fabric. You wouldn't typically use this approach within a Fabric-based app.
1. Try generating a class name using `mergeStyles` and use it as a `className` prop inside `TodoApp` 1. Try generating a class name using `mergeStyles` and use it as a `className` prop inside `TodoApp`

Просмотреть файл

@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos - step2-03 exercise</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.3 exercise)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -8,8 +8,8 @@ We will solve these problems with the [React Context API](https://reactjs.org/do
1. The problem of complex applications 1. The problem of complex applications
2. React Context API 2. React Context API
3. Consuming context from a Class Component 3. Consuming context from a class component
4. Consuming context from a Functional Component 4. Consuming context from a functional component
## The problem of complex applications ## The problem of complex applications
@ -81,7 +81,7 @@ class TodoApp extends React.Component {
} }
``` ```
### Consume context from a Class Component ### Consume context from a class component
Inside a class-based child component, such as `<TodoHeader>`, the context created in the parent can be accessed via `this.context`. Note that for this to work, you must also set the component class's `contextType` property to the context type created above. Inside a class-based child component, such as `<TodoHeader>`, the context created in the parent can be accessed via `this.context`. Note that for this to work, you must also set the component class's `contextType` property to the context type created above.
@ -97,7 +97,7 @@ class TodoHeader extends React.Component {
TodoHeader.contextType = TodoContext; TodoHeader.contextType = TodoContext;
``` ```
### Consume context from a Functional Component ### Consume context from a functional component
If you're using the functional component syntax, you can access the context with the `useContext()` hook: If you're using the functional component syntax, you can access the context with the `useContext()` hook:

Просмотреть файл

@ -17,7 +17,7 @@ export class TodoHeader extends React.Component<{}, TodoHeaderState> {
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.4 demo)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -4,19 +4,19 @@
If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 4 to see results. If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 4 to see results.
## TodoContext.Provider Component ## TodoContext.Provider component
1. Open `exercise/src/components/TodoApp.tsx` 1. Open `exercise/src/components/TodoApp.tsx`
2. Uncomment the missing functions inside the value prop 2. Uncomment the missing functions inside the value prop
## TodoFooter, Context inside Functional Component ## TodoFooter: context inside functional component
1. Open `exercise/src/components/TodoFooter.tsx` 1. Open `exercise/src/components/TodoFooter.tsx`
2. Use `useContext` to access the `TodoContext` and replace the two constants with values from the context 2. Use `useContext` to access the `TodoContext` and replace the two constants with values from the context
## TodoHeader, Context inside Class Component ## TodoHeader: context inside class component
1. Open `exercise/src/components/TodoHeader.tsx` 1. Open `exercise/src/components/TodoHeader.tsx`

Просмотреть файл

@ -17,7 +17,7 @@ export class TodoHeader extends React.Component<{}, TodoHeaderState> {
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.4 exercise)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.5: Redux: Reducers (Exercise) # Step 2.5 - Redux: The Store (Exercise)
[Lessons](../../) | [Demo](../demo/) [Lessons](../../) | [Demo](../demo/)
@ -6,12 +6,12 @@ If you don't already have the app running, start it by running `npm start` from
1. First, take a look at the store interface in `exercise/src/store/index.ts`. Note that the `Store` interface has two keys: `todos` and `filter`. We'll concentrate on `todos`, which is an object where the keys are string IDs and the values are of type `TodoItem`. 1. First, take a look at the store interface in `exercise/src/store/index.ts`. Note that the `Store` interface has two keys: `todos` and `filter`. We'll concentrate on `todos`, which is an object where the keys are string IDs and the values are of type `TodoItem`.
2. Open `exercise/src/reducers/index.ts` and fill in the missing case statements for the switch on `action.type`. 2. Open `exercise/src/reducers/index.ts` and fill in the missing reducer implementations.
3. Open `exercise/src/index.tsx` and write separate dispatch calls. 3. Open `exercise/src/index.tsx` and write some `dispatch` calls.
4. Take a look what is written in the console (F12 on PC, cmd-option-I on Mac). 4. Take a look what is written in the console (F12 on PC, `cmd-option-I` on Mac).
5. Install the Redux DevTools [Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) extensions 5. Install the Redux DevTools [Chrome](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) or [Firefox](https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/) extension
6. Observe the state changes and try doing "time travel" 6. Observe the state changes and try doing "time travel"

Просмотреть файл

@ -1,4 +1,4 @@
# Step 2.6: Redux: React Binding (Demo) # Step 2.6 - Redux: React binding (Demo)
[Lessons](../../) | [Exercise](../exercise/) [Lessons](../../) | [Exercise](../exercise/)

Просмотреть файл

@ -23,7 +23,7 @@ class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.6 demo)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -1,14 +1,14 @@
# Step 2.6: Redux: React Binding (Exercise) # Step 2.6 - Redux: React binding (Exercise)
[Lessons](../../) | [Demo](../demo/) [Lessons](../../) | [Demo](../demo/)
If you haven't arStart the app by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 6 to see results. If you don't already have the app running, start it by running `npm start` from the root of the `frontend-bootcamp` folder. Click the "exercise" link under day 2 step 6 to see results.
At the beginning of this exercise, the "Add" and "Clear Completed" buttons do not work. We'll be fixing that in this step! At the beginning of this exercise, the "Add" and "Clear Completed" buttons do not work. We'll be fixing that in this step!
1. Open `exercise/src/index.tsx` and wrap `<TodoApp>` with `<Provider>` as instructed in the comment 1. Open `exercise/src/index.tsx` and wrap `<TodoApp>` with `<Provider>` as instructed in the comment
2. Open `exercise/src/components/TodoFooter.tsx` and erase the "nullable" type modifier (i.e. the ?) in the interface definition of `TodoFooterProps` 2. Open `exercise/src/components/TodoFooter.tsx` and erase the "nullable" type modifier (the `?`) in the interface definition of `TodoFooterProps`
3. Uncomment the bottom bits of code and fill in `connect()` arguments - feel free to use `TodoListItem.tsx` as a guide 3. Uncomment the bottom bits of code and fill in `connect()` arguments - feel free to use `TodoListItem.tsx` as a guide

Просмотреть файл

@ -25,7 +25,7 @@ class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
return ( return (
<Stack gap={10}> <Stack gap={10}>
<Stack horizontal horizontalAlign="center"> <Stack horizontal horizontalAlign="center">
<Text variant="xxLarge">todos</Text> <Text variant="xxLarge">todos <Text variant="mediumPlus">(2.6 exercise)</Text></Text>
</Stack> </Stack>
<Stack horizontal gap={10}> <Stack horizontal gap={10}>

Просмотреть файл

@ -40,10 +40,13 @@ fs.readdirSync('./').filter(step => {
if (!isEntryPoint && isValidLessonFolder(step)) { if (!isEntryPoint && isValidLessonFolder(step)) {
nonWebpackedEntries.push(step); nonWebpackedEntries.push(step);
} else if (step === 'step1-04') {
// special case: this folder's `final` has code, but its `demo` doesn't
nonWebpackedEntries.push('step1-04/demo');
} }
}); });
module.exports = function(env, argv) { module.exports = function (env, argv) {
return { return {
entry: { ...entries, markdownReadme: './markdownReadme/src/index.ts' }, entry: { ...entries, markdownReadme: './markdownReadme/src/index.ts' },
module: { module: {