This commit is contained in:
Micah Godbolt
2019-02-22 17:09:35 -08:00
15 changed files with 168 additions and 39 deletions

BIN
assets/flux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -152,17 +152,15 @@ Please complete all exercises inside the `exercise/src` folder unless otherwise
Create inside `index.ts`:
1. a type alias for string union type describing the states of Red-Green-Yellow traffic light
1. a type alias for string union type describing the states of Red-Green-Yellow traffic light: `type TrafficLight = ???`
2. a class hierarchy of your favorite metaphor (e.g. family, autombiles, animals)
3. describe an object type with an interface
2. describe a type of car with an interface: `interface Car { ... }`
## Generic
Inside `index.ts`, create a generic class for a `Stack<T>` complete with a typed `pop()` and `push()` methods
Inside `stack.ts`, create a generic class for a `Stack<T>` complete with a typed `pop()` and `push()` methods
Hint: the Javascript array already has `push()` and `pop()` implemented for you. That can be your backing store.
> Hint: the Javascript array already has `push()` and `pop()` implemented for you. That can be your backing store.
Be sure to use the provided `log()` to show the functionality of `Stack<T>`

View File

@@ -0,0 +1,10 @@
// TODO: create a Stack<T> generic class here:
/**
*
* export class Stack<T> {
* push(...) { ... }
* pop(...) { ... }
* }
*
*/

View File

@@ -15,10 +15,16 @@ https://developer.microsoft.com/en-us/fabric/#/components
# Exercise
- Open up the TSX files inside `components/`
- Replace the DOM tags with Fabric components in those TSX files with these components:
- Stack
- DefaultButton
- Checkbox
- TextField
- Pivot (for the filter)
1. Open up the Documentation for DefaultButton here:
2. Open up the TSX files inside `components/`
3. Replace the DOM tags with Fabric components in those TSX files with these components:
- Stack
- DefaultButton
- Checkbox
- TextField
- Pivot (for the filter)
# Bonus Exercise
GO WILD! There are so many components from the Fabric library! Try to put some components in the exercise component files.

View File

@@ -2,6 +2,36 @@
Theming and Styling with UI Fabric. In this section, we will illustrate how to utilize some of the built-in theming and styling features right inside UI Fabric component library. UI Fabric exposes its own css-in-js library called `mergeStyles` that is very performant compared with other similar libraries.
A CodePen that illustrates what `mergeStyles` does: https://codepen.io/dzearing/pen/jGdgrE?editors=1011
There are three areas that we should focus on in this step:
1. Theming with Fabric
2. CSS-in-JS with mergeStyles
3. Customizing Fabric Components `styles` prop
## 1. Theming with Fabric
- Fabric applies themes by propagating the theme down the children through the React Context mechanism
- It is applied with the `<Customizer>` component
- There are some predefined themes within Fabric already, like Fluent (which will become the default in the next major), MDL2, Azure, and some other sample themes like Teams.
- Take a look at `demo/src/components/TodoApp.tsx`
## 2. CSS-in-JS with mergeStyles
- `mergeStyles` is a styling library that creates CSS class from styles that are expressed in JS
- These classes can be passed into `className` prop of any component like `<div>`
- This library replaces the need to import CSS stylesheets because they are bundled as normal JS code
- Take a look at `demo/src/components/TodoApp.tsx`
## 3. Customizing Fabric Controls
- calling `mergeStyles` is time consuming and very static
- Fabric components expose a `styles` prop (not to be confused with the React built-in one called `style`)
- You can use intellisense to discover which parts of the component you can to customize
- You can even use a style function to change the style based on some style prop
- Take a look at these customizations in `demo/src/components/TodoHeader.tsx`
# Exercises
## Themes - Using Predefined Theme
@@ -63,7 +93,7 @@ loadTheme({
The styling library name is glamorous nor does it bring about emotion, but it is very quick and lightweight. `MergeStyles` turns CSS Rules into CSS class names to be applied to the components.
1. Try applying a merged style `className` as a prop inside any component that you would find.
1. Try applying a merged style `className` as a prop inside `TodoApp`
```tsx
import { mergeStyles } from 'office-ui-fabric-react';
@@ -79,3 +109,13 @@ const className = mergeStyles({
```
2. Try to give a few components extra padding
## Customize the Fabric Components
1. Open `exercise/src/components/TodoFooter.tsx`
2. Find the `<DefaultButton>` and insert a `styles` prop
3. Try to customize this with a styles object (let the Intellisense of VS Code guide you on what you can use to customize)
4. Try to customize this with a styles function

View File

@@ -29,9 +29,22 @@ export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState
<Stack horizontal gap={10}>
<Stack.Item grow>
<TextField placeholder="What needs to be done?" value={this.state.labelInput} onChange={this.onChange} />
<TextField
placeholder="What needs to be done?"
value={this.state.labelInput}
onChange={this.onChange}
styles={props => ({
...(props.focused && {
field: {
backgroundColor: 'black'
}
})
})}
/>
</Stack.Item>
<PrimaryButton onClick={this.onAdd}>Add</PrimaryButton>
<PrimaryButton onClick={this.onAdd} styles={{ root: { backgroundColor: 'maroon' }, rootHovered: { background: 'green' } }}>
Add
</PrimaryButton>
</Stack>
<Pivot onLinkClick={this.onFilter}>

View File

@@ -10,6 +10,7 @@ import { TeamsCustomizations } from '@uifabric/theme-samples';
let index = 0;
// TODO: Change this to add other CSS styles like backgroundColor, fontSize, etc
const className = mergeStyles({
padding: 25,
...getTheme().effects.elevation4

View File

@@ -12,6 +12,9 @@ interface TodoFooterProps {
export const TodoFooter = (props: TodoFooterProps) => {
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
// TODO: play around with the DefaultButton component below with a "styles" prop
// - try it with an object: styles={{ ... }}
// - try it with a function: styles={props => ({ ... })}
return (
<Stack horizontal horizontalAlign="space-between">
<Text>

View File

@@ -2,14 +2,30 @@
Testing Typescript code with jest. jest is a test framework made by Facebook and is very popular in the React and the wider JS ecosystem. We will work on implementing simple unit tests here in this exercise.
We won't go too deeply into mocks in this exercise, but feel free to play around with that yourself by reading up on this:
https://jestjs.io/
https://jestjs.io/docs/en/mock-functions
- Multi-threaded and isolated test runner
- Provides a "fake" browser environment if needed (window, document, DOM, etc).
- Snapshots: show API or large object changes along side code changes in pull requests
- Code coverage is integrated (--coverage)
- Very clear error messages of where the test failures occur
# Demo
In this repo, we can start an inner loop development of tests with the command: `npm test`
Take a look at code inside `demo/src`:
1. `index.ts` is exports a few functions for a counter as well as a test for squaring numbers but demonstrates out jest uses mocks
2. `multiply.ts` is a contrived example of a function that is exported
3. `index.spec.ts` is the test file: note how tests are re-run on save to test file changes as well as source code changes under `src`
# Exercise
1. copy the generic `Stack<T>` code you have developed in Step 2.1
1. Run the tests by running `npm test` at the root of the bootcamp project
2. Run the tests by running `npm test` at the root of the bootcamp project
2. Look at the `stack.ts` for a sample implementation of a stack
3. Follow the instructions inside the `stack.spec.ts` file to complete the two tests

View File

@@ -1,13 +1,20 @@
import { square } from '.';
import { multiply } from './multiply';
// Mocked here by jest for the entire test module file
jest.mock('./multiply');
describe('jest example', () => {
beforeEach(() => {
jest.resetModules();
});
it('should be able to give the square of two numbers', () => {
console.log('test');
expect(square(5)).toBe(25);
it('should be passing in the multiple two of the same number', () => {
square(5);
// .toBeCalledTimes() and .toBeCalledWith() only work on mocks - we mocked the multiply function from the
expect(multiply).toBeCalledTimes(1);
expect(multiply).toBeCalledWith(5, 5);
});
it('should increment counter', () => {

View File

@@ -1,3 +1,5 @@
import { multiply } from './multiply';
let counter = 0;
export function getCount() {
@@ -13,5 +15,5 @@ export function decrement() {
}
export function square(x: number) {
return x * x;
return multiply(x, x);
}

View File

@@ -0,0 +1,3 @@
export function multiply(x: number, y: number) {
return x * y;
}

View File

@@ -1,14 +0,0 @@
export type FilterTypes = 'all' | 'active' | 'completed';
export interface TodoItem {
label: string;
completed: boolean;
}
export interface Store {
todos: {
[id: string]: TodoItem;
};
filter: FilterTypes;
}

View File

@@ -1 +1,13 @@
// Place your implementation from Step 2-01 exercise here
export class Stack<T> {
private _items: T[] = [];
push(item: T) {
this._items.push(item);
}
pop(): T {
if (this._items.length > 0) {
return this._items.pop();
}
}
}

View File

@@ -1,5 +1,37 @@
# Step 2.5: Redux: Reducers
Redux is an implementation of the Flux architectural pattern:
![Flux Diagram](../assets/flux.png)
Ideally React gives us a mental model of:
```
f(data) => view
```
And it renders when data changes. However, in the real world, data is shaped like a tree and view is shaped like a tree. They don't always match. There are many approaches to Flux, but Redux promotes the data into a singleton state tree that listens for messages to manipulate the state as appropriate.
## View
These are the React Components that consume the store as its data. There is a special way Redux will map its data from the state tree into the different React Components. The Components will know to re-render when these bits of state are changed.
## Store
This is a singleton state tree. The state tree is immutable and needs to be re-created at every action. This helps connected views to know when to update itself - just doing a simple reference comparison rather than a deep comparison.
## Action
Actions are messages to be dispatched to the store to let reducers to change (replace reference of) the state tree.
## Reducers
These are simple stateless, pure functions that takes state + action message and returns a copy of state some modifications according to the action message type and payload.
## Dispatcher
There is a single dispatcher. It simply informs of the store of all the actions that needs to be performed. Certain middleware can be applied to the store and the dispatcher's job is to dispatch the message through all the middleware layers.
Redux is used inside many large and complex applications because of its clarity and its predictability. It is really easy to debug and is easily extensible via its middleware architecture. In this exercise, we'll explore the heart of how Redux modifies state.
Redux uses what is called a "reducer" to modify its state. It is called this because a "reducer" is what is used inside an `Array.reduce()`.