diff --git a/assets/flux.png b/assets/flux.png new file mode 100644 index 0000000..9286f70 Binary files /dev/null and b/assets/flux.png differ diff --git a/step2-01/README.md b/step2-01/README.md index 753bd64..15733d2 100644 --- a/step2-01/README.md +++ b/step2-01/README.md @@ -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` complete with a typed `pop()` and `push()` methods +Inside `stack.ts`, create a generic class for a `Stack` 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` diff --git a/step2-01/exercise/src/stack.ts b/step2-01/exercise/src/stack.ts new file mode 100644 index 0000000..99d1ad3 --- /dev/null +++ b/step2-01/exercise/src/stack.ts @@ -0,0 +1,10 @@ +// TODO: create a Stack generic class here: + +/** + * + * export class Stack { + * push(...) { ... } + * pop(...) { ... } + * } + * + */ diff --git a/step2-02/README.md b/step2-02/README.md index 3e1011e..a5cfe10 100644 --- a/step2-02/README.md +++ b/step2-02/README.md @@ -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. diff --git a/step2-03/README.md b/step2-03/README.md index eb3ec4c..f5bf00d 100644 --- a/step2-03/README.md +++ b/step2-03/README.md @@ -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 `` 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 `
` +- 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 `` 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 diff --git a/step2-03/demo/src/components/TodoHeader.tsx b/step2-03/demo/src/components/TodoHeader.tsx index 7a9cae2..9a56b33 100644 --- a/step2-03/demo/src/components/TodoHeader.tsx +++ b/step2-03/demo/src/components/TodoHeader.tsx @@ -29,9 +29,22 @@ export class TodoHeader extends React.Component - + ({ + ...(props.focused && { + field: { + backgroundColor: 'black' + } + }) + })} + /> - Add + + Add + diff --git a/step2-03/exercise/src/components/TodoApp.tsx b/step2-03/exercise/src/components/TodoApp.tsx index c7e0c35..4d52c64 100644 --- a/step2-03/exercise/src/components/TodoApp.tsx +++ b/step2-03/exercise/src/components/TodoApp.tsx @@ -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 diff --git a/step2-03/exercise/src/components/TodoFooter.tsx b/step2-03/exercise/src/components/TodoFooter.tsx index 6a44d83..e806563 100644 --- a/step2-03/exercise/src/components/TodoFooter.tsx +++ b/step2-03/exercise/src/components/TodoFooter.tsx @@ -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 ( diff --git a/step2-04/README.md b/step2-04/README.md index 4bb0b02..0633334 100644 --- a/step2-04/README.md +++ b/step2-04/README.md @@ -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` 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 diff --git a/step2-04/demo/src/index.spec.ts b/step2-04/demo/src/index.spec.ts index 87620da..81d4418 100644 --- a/step2-04/demo/src/index.spec.ts +++ b/step2-04/demo/src/index.spec.ts @@ -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', () => { diff --git a/step2-04/demo/src/index.ts b/step2-04/demo/src/index.ts index 0ac7fff..ecdd946 100644 --- a/step2-04/demo/src/index.ts +++ b/step2-04/demo/src/index.ts @@ -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); } diff --git a/step2-04/demo/src/multiply.ts b/step2-04/demo/src/multiply.ts new file mode 100644 index 0000000..aa528c0 --- /dev/null +++ b/step2-04/demo/src/multiply.ts @@ -0,0 +1,3 @@ +export function multiply(x: number, y: number) { + return x * y; +} diff --git a/step2-04/demo/src/store/index.ts b/step2-04/demo/src/store/index.ts deleted file mode 100644 index 221b5f4..0000000 --- a/step2-04/demo/src/store/index.ts +++ /dev/null @@ -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; -} diff --git a/step2-04/exercise/src/stack.ts b/step2-04/exercise/src/stack.ts index 52c8311..267a771 100644 --- a/step2-04/exercise/src/stack.ts +++ b/step2-04/exercise/src/stack.ts @@ -1 +1,13 @@ -// Place your implementation from Step 2-01 exercise here +export class Stack { + private _items: T[] = []; + + push(item: T) { + this._items.push(item); + } + + pop(): T { + if (this._items.length > 0) { + return this._items.pop(); + } + } +} diff --git a/step2-05/README.md b/step2-05/README.md index 66d2f10..9a98566 100644 --- a/step2-05/README.md +++ b/step2-05/README.md @@ -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()`.