Merge branch 'master' of github.com:Microsoft/frontend-bootcamp
This commit is contained in:
Коммит
a2c2b0f3e9
83
README.md
83
README.md
|
@ -6,7 +6,7 @@
|
|||
|
||||
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
|
||||
|
||||
|
@ -23,88 +23,75 @@ Before starting, make sure your computer has up-to-date versions of the followin
|
|||
|
||||
### 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
|
||||
- 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 `npm install` to install of the project dependencies
|
||||
- Type `code ./` to open the bootcamp code in VS Code
|
||||
- Type `npm install` to install all of the project dependencies
|
||||
- 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.
|
||||
|
||||
### 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 />
|
||||
|
||||
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:
|
||||
1. press `ctrl + c` to stop the static inner loop
|
||||
|
||||
```
|
||||
npm run start
|
||||
```
|
||||
|
||||
Both of these above commands will load the following site:
|
||||
This will load the site shown below.
|
||||
|
||||
<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 is going to cover 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)
|
||||
Day one covers the basics of HTML, CSS and JavaScript, as well as an introduction to React and Typescript.
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
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)
|
||||
### Bonus content
|
||||
|
||||
### Additional resources
|
||||
* [Redux: Service calls](bonus-servicecalls)
|
||||
* [Testing with Jest](bonus-jest)
|
||||
|
||||
## Additional resources
|
||||
|
||||
- [MDN Web Docs](https://developer.mozilla.org/en-US/)
|
||||
- [React Docs](https://reactjs.org/docs/getting-started.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:
|
||||
|
||||
- [@kenneth_chau](https://twitter.com/kenneth_chau)
|
||||
- [@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)
|
||||
- [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.
|
||||
|
||||
## Jest Features
|
||||
## Jest features
|
||||
|
||||
- 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.
|
||||
- Code coverage is integrated (`--coverage`)
|
||||
- Very clear error messages showing where a test failure occurred
|
||||
|
||||
## 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!
|
||||
- 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`
|
||||
- in order to use `enzyme` library to test React Components, more config bits are needed inside `jest.setup.js`
|
||||
Using `create-react-app` or other project generators, Jest should already be pre-configured. Running `npm test` usually will trigger it!
|
||||
|
||||
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).
|
||||
|
||||
## What does a test look like?
|
||||
|
||||
```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', () => {
|
||||
it('should describe the behavior', () => {
|
||||
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
|
||||
|
||||
[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).
|
||||
|
||||
### 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.
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
</li>
|
||||
<li class="Tile Tile--numbered">
|
||||
<div class="Tile-link">
|
||||
jest: testing code
|
||||
Testing with Jest
|
||||
<div class="Tile-links">
|
||||
<a target="_blank" href="./bonus-jest/demo/">demo</a> | <a target="_blank" href="./bonus-jest/exercise/">exercise</a>
|
||||
</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.
|
||||
|
||||
|
@ -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)
|
||||
|
||||
# HTML Demo
|
||||
## HTML demo
|
||||
|
||||
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).
|
||||
|
||||
## Sample Website
|
||||
## Sample webpage
|
||||
|
||||
```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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### Applying CSS to an HTML file
|
||||
## Applying CSS to an HTML file
|
||||
|
||||
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
|
||||
- `<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**.
|
||||
|
|
@ -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.
|
|
@ -25,7 +25,7 @@
|
|||
/* Bonus */
|
||||
</pre>
|
||||
<pre data-lang="html">
|
||||
<!-- Without changing the below markup apply the styles asked for in the markup. Do not apply styles that a tag doesn't ask for -->
|
||||
<!-- Without changing the HTML markup, apply the styles asked for in the markup. Do not apply styles that a tag doesn't ask for. -->
|
||||
|
||||
<section>
|
||||
<h2>1. Text Color: Red</h2>
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -20,7 +20,7 @@ By the end of the demo we'll have covered the following:
|
|||
- Loops
|
||||
- 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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### Variable Examples
|
||||
### Variable examples
|
||||
|
||||
```js
|
||||
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.
|
||||
|
||||
### 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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### 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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### 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:
|
||||
|
||||
|
@ -208,7 +208,3 @@ function displayMatches() {
|
|||
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')`.
|
||||
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.
|
||||
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.
|
|
@ -29,15 +29,32 @@ button {
|
|||
</pre>
|
||||
<pre data-lang="js">
|
||||
/*
|
||||
1. Create a function named `getFavs` and set its contents to `alert('clicked')`
|
||||
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 it calls our alert.
|
||||
4. Replace the alert 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. For 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. Pass that text into `favList.push()` as the parameter to add it to the array
|
||||
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.
|
||||
1. Create a function named `getFavs`. Inside, run:
|
||||
alert('clicked')
|
||||
|
||||
2. Create a variable `button` and set it to a reference to our button 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` 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>
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -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' />`
|
||||
- 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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
## 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.
|
||||
|
||||
> 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`;
|
||||
|
||||
|
@ -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`).
|
||||
- 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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -235,11 +235,11 @@ Add a couple `Counter`s to our `App`, each with different text. Notice how they
|
|||
|
||||
## 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
|
||||
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.
|
||||
|
||||
#### Default Exports
|
||||
#### Default exports
|
||||
|
||||
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';
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
|
|
|
@ -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>
|
||||
<body>
|
||||
<header>
|
||||
<h1>todos</h1>
|
||||
<h1>todos <small>(1.5)</small></h1>
|
||||
<div class="addTodo">
|
||||
<input class="textfield" placeholder="add todo" />
|
||||
<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
|
||||
- TodoList
|
||||
- TodoListItem
|
||||
- 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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -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`
|
||||
|
||||
### TodoList
|
||||
## TodoList
|
||||
|
||||
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]`
|
||||
|
||||
## App.tsx
|
||||
## App
|
||||
|
||||
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() {
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-05 exercise</h1>
|
||||
<h1>todos <small>(1.5 exercise)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input className="textfield" placeholder="add todo" />
|
||||
<button className="submit">Add</button>
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
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.
|
||||
|
||||
[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:
|
||||
|
||||
|
@ -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.
|
||||
|
||||
## Passing State Through to UI
|
||||
## Passing state through to UI
|
||||
|
||||
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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### 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**.
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
const { filter } = this.props;
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-06 demo</h1>
|
||||
<h1>todos <small>(1.6 demo)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input className="textfield" placeholder="add todo" />
|
||||
<button className="submit">Add</button>
|
||||
|
|
|
@ -12,7 +12,7 @@ export class TodoList extends React.Component<any, any> {
|
|||
|
||||
return (
|
||||
<ul className="todos">
|
||||
[01, 02, 03, 04].map((id)=> <TodoListItem />)
|
||||
{['01', '02', '03', '04'].map((id) => <TodoListItem />)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
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.
|
||||
|
||||
### TodoFooter
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-06 exercise</h1>
|
||||
<h1>todos <small>(1.6 exercise)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
|
||||
<button className="submit">Add</button>
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
|
||||
> 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
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
const { filter } = this.props;
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-07 demo</h1>
|
||||
<h1>todos <small>(1.7 demo)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
|
||||
<button className="submit">Add</button>
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
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
|
||||
|
||||
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`.
|
||||
|
||||
> 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.
|
||||
|
||||
|
@ -14,13 +17,14 @@
|
|||
|
||||
## 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
|
||||
|
||||
> 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
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
const { filter } = this.props;
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-07 exercise</h1>
|
||||
<h1>todos <small>(1.7 exercise)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
|
||||
<button className="submit">Add</button>
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
|
|||
const { filter, setFilter } = this.props;
|
||||
return (
|
||||
<header>
|
||||
<h1>todos - step1-07 final</h1>
|
||||
<h1>todos <small>(1.7 final)</small></h1>
|
||||
<div className="addTodo">
|
||||
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
|
||||
<button onClick={this._onAdd} className="submit">
|
||||
|
|
|
@ -8,6 +8,10 @@ h1 {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
|
||||
.addTodo {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Step 2.1: Introduction to TypeScript (Demo)
|
||||
# Step 2.1 - Introduction to TypeScript (Demo)
|
||||
|
||||
[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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
|
@ -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).
|
||||
|
||||
## 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:
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Step 2.1: Introduction to TypeScript (Exercise)
|
||||
# Step 2.1 - Introduction to TypeScript (Exercise)
|
||||
|
||||
[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)`.
|
||||
|
||||
## Types and Interfaces
|
||||
## Types and interfaces
|
||||
|
||||
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.
|
||||
|
||||
## Spread and Destructuring
|
||||
## Spread and destructuring
|
||||
|
||||
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`.
|
||||
|
||||
## Async / Await
|
||||
## Async / await
|
||||
|
||||
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/)
|
||||
|
||||
|
@ -11,7 +11,7 @@ We'll talk about:
|
|||
- [How to use it](#how-to-use-it)
|
||||
- [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
|
||||
- Most notable Microsoft web products use it
|
||||
|
@ -23,7 +23,7 @@ We'll talk about:
|
|||
- Engineering is done in the open on GitHub
|
||||
- Engineering system is shared and re-usable by other teams
|
||||
|
||||
## How to Find It
|
||||
## How to find it
|
||||
|
||||
GitHub repo:
|
||||
https://github.com/officedev/office-ui-fabric-react
|
||||
|
@ -31,9 +31,9 @@ https://github.com/officedev/office-ui-fabric-react
|
|||
Documentation:
|
||||
https://developer.microsoft.com/en-us/fabric/#/components
|
||||
|
||||
## How to Use It
|
||||
## How to use it
|
||||
|
||||
### Importing a Component
|
||||
### Importing a component
|
||||
|
||||
```jsx
|
||||
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).
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -84,7 +84,7 @@ const MyComponent = () => {
|
|||
|
||||
## 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 tool: http://the-echoplex.net/flexyboxes/
|
||||
|
|
|
@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
|
|||
return (
|
||||
<Stack>
|
||||
<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 horizontal>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Step 2.2: UI Fabric Component Library (Exercise)
|
||||
# Step 2.2 - UI Fabric component library (Exercise)
|
||||
|
||||
[Lessons](../../) | [Demo](../demo/)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
|
|||
return (
|
||||
<Stack>
|
||||
<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 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/)
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
<Text variant="xxLarge">todos <Text variant="mediumPlus">(2.3 demo)</Text></Text>
|
||||
</Stack>
|
||||
|
||||
<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/)
|
||||
|
||||
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:
|
||||
|
||||
|
@ -20,7 +18,7 @@ with:
|
|||
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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
### Customizing one Fabric control instance
|
||||
## Customizing one Fabric control instance
|
||||
|
||||
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
|
||||
|
||||
## 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`
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<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 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
|
||||
2. React Context API
|
||||
3. Consuming context from a Class Component
|
||||
4. Consuming context from a Functional Component
|
||||
3. Consuming context from a class component
|
||||
4. Consuming context from a functional component
|
||||
|
||||
## 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.
|
||||
|
||||
|
@ -97,7 +97,7 @@ class TodoHeader extends React.Component {
|
|||
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:
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export class TodoHeader extends React.Component<{}, TodoHeaderState> {
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
<Text variant="xxLarge">todos <Text variant="mediumPlus">(2.4 demo)</Text></Text>
|
||||
</Stack>
|
||||
|
||||
<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.
|
||||
|
||||
## TodoContext.Provider Component
|
||||
## TodoContext.Provider component
|
||||
|
||||
1. Open `exercise/src/components/TodoApp.tsx`
|
||||
|
||||
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`
|
||||
|
||||
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`
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ export class TodoHeader extends React.Component<{}, TodoHeaderState> {
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
<Text variant="xxLarge">todos <Text variant="mediumPlus">(2.4 exercise)</Text></Text>
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal gap={10}>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Step 2.5: Redux: Reducers (Exercise)
|
||||
# Step 2.5 - Redux: The Store (Exercise)
|
||||
|
||||
[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`.
|
||||
|
||||
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"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Step 2.6: Redux: React Binding (Demo)
|
||||
# Step 2.6 - Redux: React binding (Demo)
|
||||
|
||||
[Lessons](../../) | [Exercise](../exercise/)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
<Text variant="xxLarge">todos <Text variant="mediumPlus">(2.6 demo)</Text></Text>
|
||||
</Stack>
|
||||
|
||||
<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/)
|
||||
|
||||
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!
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
|
|||
return (
|
||||
<Stack gap={10}>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
<Text variant="xxLarge">todos <Text variant="mediumPlus">(2.6 exercise)</Text></Text>
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal gap={10}>
|
||||
|
|
|
@ -40,10 +40,13 @@ fs.readdirSync('./').filter(step => {
|
|||
|
||||
if (!isEntryPoint && isValidLessonFolder(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 {
|
||||
entry: { ...entries, markdownReadme: './markdownReadme/src/index.ts' },
|
||||
module: {
|
||||
|
|
Загрузка…
Ссылка в новой задаче