GithubHelp home page GithubHelp logo

coryhouse / reactjsconsulting Goto Github PK

View Code? Open in Web Editor NEW
379.0 19.0 38.0 18.31 MB

React Related Resources

Home Page: http://www.reactjsconsulting.com

JavaScript 84.51% HTML 2.48% CSS 3.66% TypeScript 2.99% Shell 0.07% SCSS 6.29%

reactjsconsulting's Introduction

Prerequisites

Please do these steps before the event. If you have any problems, email [email protected].

  1. Install Node 10 or newer
  2. Install Git
  3. Install VS Code
  4. Install these VS Code extensions: Prettier, ESLint, and React Code Snippets
  5. Click the green "Clone this template" button above.
  6. Enter a name and descripion for your repo. Click "Create Repository from Template"
  7. Open a command line to the directory where you cloned this repo
  8. Change directories into the dev-environment directory
  9. Run this command to install dependencies: npm install
  10. Run this command to start the app: npm start
  11. Load http://localhost:3000. You should see the app start.
  12. Load http://localhost:3001. You should see json-server's landing page.

If you did all the above, you're all set!

Keep in Touch!

reactjsconsulting's People

Contributors

coryhouse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactjsconsulting's Issues

Finite State machines

Note: State Enums provide some of the benefits without all the complexity of learning state charts and XState.

Key Terms

  • Event - An external signal that something happened. Events are sent to the state machine. An event sets of a transition.
    • Examples: INPUT (User typed a key). SUBMIT (User submitted a form). RESOLVE (Promise resolved). In XState, the on key holds the event name.
  • Action -
  • States - Discrete states
  • Transition - A change from one state to another
  • Activity - Use for ongoing activities like an alarm clock that writes to the console every second.

Blog overview - State machines in React
Blog - Model based testing in React via state machines - Blog based version of David K Piano's React Rally talk
XState
XState Visualizer
XState Catalog

Examples

https://github.com/cypress-io/cypress-realworld-app
https://mastery.games/post/state-machines-in-react/
Multistep form: https://codesandbox.io/s/crckp?file=/src/stepMachine.js

Session Intro

Intro

  • Who is this guy?
  • Name tags
  • Introductions
    • Name
    • Role
    • JS experience
    • React experience
    • Server side tech experience
    • What you're hoping to learn
  • What are you building?
    • Browser support
  • What is your development background?
    • Biggest frustrations with current dev setup
    • What is your current JS experience?
  • Why did you select React?
  • What do you already know about React? Are you comfortable with the prerequisites above?
  • What preferences do you already have?
    • Types
    • State management
    • Styling
    • Testing
    • Server rendering
    • Mobile

My Goals

Leverage what makes in-person training so effective:

  1. Encourage metacognition (thinking about thinking). Foster active thinking, structuring, and validating your understanding.
  2. Get you as excited to continue exploring on your own.
  3. You control your learning experience. Be interactive, like a video game. You help guide pace, implementation, and order.

The 6 Core Learning Techniques

  1. Retrieval - Practice recalling. Quiz yourself. "Our brains are like a forest. The memory is in there somewhere. Retrieving memories creates a path through that forest. The memory gets easier to retrieve each time we try to find it in the forest." Practicing retrieval makes memory stick far better than reviewing the material again.
  2. Spacing - Time between retrieval avoids forgetting. Short-term repetition is a waste of time. If it’s easy to recall because it was just taught, you’re not learning. You’re merely repeating. Memory is forged by spaced retrieval (Time in between quizzes). Retrieving memories changes the way they are later encoded. The harder something is to remember now, the better we will recall it in the future. The more we strain, the easier it will be in the future.
  3. Interleaving - Moving between topics aids retention because it naturally spaces out retrieval. Quit the current topic and move on to something else before you actually feel like you’ve mastered that topic. Yes, it’s frustrating to leave before you’re ready. This admittedly feels slower in the short-term. But doing so helps you learn. Making errors is an integral part of learning. Making errors is a sign that you’re on the right track and pushing.
  4. Variation - Retrieve in random order. Jump around. Shuffle quiz note cards. (Story: Students who practiced throwing bean bags at varied distances even beat those who practiced solely on 3 ft distance). The real world will present concepts in random order and contexts. So variation in examples, contexts, order, etc fosters the ability to recall what you’ve learned and recognize patterns in the real world. NFL players randomize plays and exercises during practice.
  5. Reflection - Think about how the concept fits within your existing knowledge. It’s easier to learn a new concept when we ground it in something we already know. What is this like? What can you compare to? What mistakes did you make? We learn better when we are presented with the challenge before being shown the solution. The act of trying to solve it helps us learn. It’s better to solve a problem then to memorize a solution. And it’s better to attempt a solution and provide the incorrect answer then it is to not make the attempt.
  6. Elaboration - Describe what you’re learning. Explain in your own words. Learning is an act of engagement. You learn by trying to make sense of something new. You don’t engage by watching. You engage by explaining in your own words and relating to what you already know. Embrace the Feynman technique: "If you can’t explain something in simple terms, you don’t understand it" - Richard Feynman. I am okay with asking questions and standing in silence while you think. The act of thinking is helpful. The act of explanation clarifies your understanding and exposes holes. Teaching exposes sloppy understanding.

image

My Teaching Technique

  1. Retrieval - I'll regularly ask the group questions. Write or type the answers.
  2. Spacing - We'll review at three points: After each topics, and at start and end of each day.
  3. Interleaving - We'll build something real that weaves the concepts together in varied order
  4. Variation - We'll implement the concepts in different ways and discuss the merits.
  5. Reflection - I'll ask the group questions to stir reflection. Write or type your answers first. I'll even ask you questions before I've shared the answer. An unanswered question creates a slot in your brain to fill. Trying to answer a question and failing leads to better retention than merely being given the answer.
  6. Elaboration - I'll ask the group for examples of elaboration. What is this? What is this like? Why are we doing this?

Learning Tips

  • Have a growth mindset. "If you're not failing, then you're not learning" - Louise O'Neill
  • Actively engage. To understand something, you must actively engage with it. Metacognition is active.

"The more students actively engage with subject matter, the better they master material and develop critical skills. Undergraduates learn most when they’re asked to solve problems, perform original research, work collaboratively - and receive regular feedback from the professor and their peers. The passive, impersonal lecture turned out to be the worst of all possible worlds. - Arthur Chickering and Zelda Gamson, “Seven Principles for Good Practice in Undergraduate Education.”

"Lab and project work are where students learn most. The school that adopted lab/projects as the core of their approach zoomed to the first position among American engineering schools." - Education is not about learning

"What I cannot create, I do not understand." - Richard Feynman

"To learn and not to do is really not to learn. To know and not to do is really not to know." - Stephen Covey

Daily Flow

Mostly conversation and code, rather than slides

  1. Ask a leading question - What if we want to do x? Honor the 5 second rule (no, not the one about dropping your sandwich on the ground 😂)- Wait 5 seconds before answering. Give people a moment to consider the answer.
  2. Introduce concept. - Take notes on paper - You'll remember more because you'll have to paraphrase. Write in your own words. We understand ideas by thinking carefully about them.
  3. Implement together - Pair seniors with juniors. You can implement separately, but consider yourselves a team. Help each other. This helps me scale. Details in coding flow below.
  4. Review - I'll walk through the diff. I'll ask the group questions. Answer questions by writing it down or typing it out. I will call on someone to ask what their answer is. If I get the wrong answer, I will call on someone else. This will be hard. That’s the point. The fact that it’s hard says that you’re learning. You learn through practiced retrieval, explaining things in your own words, spacing, and interleaving concepts over time.
  5. Individual exercise - Try on your own (Practice retrieval, interleave, typically later for spacing). The Fogo de Chao method: Place red post-it on your laptop lid when we start an exercise. Replace with green post-it when done. When 50% of the room is green, I'll implement.
  6. Start and end of day reviews - We'll review the days topics at the start and end of each day.

Coding Flow

Having problems? Ask why your code doesn't work. We can learn from mistakes.

Option 1: Fork (recommended)

  1. I'll create a GitHub repo.
  2. I'll push to master after reviewing a feature.
  3. Fork my repo.
  4. Open a PR to merge your fork into mine. This way you can easily see how your code differs. Just refresh the PR request page after I push.
  5. Want to merge my code into your fork? Sync my fork.

Option 2: Clone

  1. Create your own repo
  2. Separately, clone my repo
  3. Want my latest code? Do a git pull on your clone of my repo.
  4. Stuck? Stage your changes, then copy/paste my code into yours. Use VS Code's diff tool to see the difference.

Final details

  • Feedback form - You can start filling it out now 🙂
  • What should we build?
  • Review agenda
  • Breaks ☕️🍩🍕🏃‍♂️💨🍺

Agenda: Responsive Web Dev at Athena Health

Agenda

Responsive Web Development

Exercise

Build a responsive component using

  • React
  • create-react-app
  • Flexbox
  • CSS modules / Sass with BEM / Emotion
  • Storybook - Document responsive design
  • Cypress - Create automated tests that validate and document responsive behavior
  • Percy

Responsive component options

  • Nav bar
  • Card
  • Form
  • Table that converts to list

TypeScript

10 JS/TS features I avoid

Tips

1. Think in sets.

  • Every type is a Set of values.
  • Some Sets are infinite: string, object; some finite: boolean, undefined.
  • unknown is Universal Set (including all values), while never is Empty Set (including no value).
  • The & operator creates an Intersection. It creates a smaller set. It must have both.
  • The | operator creates a Union: a larger Set but potentially with fewer commonly available fields (if two object types are composed).

2. Understand declared type and narrowed type

  • A variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type. You can narrow a type by checking values.

3. Use a discriminated union instead of optional fields

type Circle = { kind: 'circle'; radius: number };
type Rect = { kind: 'rect'; width: number; height: number };
type Shape = Circle | Rect;

Above, the kind property lets us discriminate. This gives us more type safety than merely using optional fields.

4. Use a type predicate to avoid type assertion

function isCircle(shape: Shape): shape is Circle {
    return shape.kind === 'circle';
}

tsconfig settings checklist for ideal safety

  • Enable strict mode
  • Enable noFallthroughCasesInSwitch
  • Enable noUncheckedIndexedAccess some argue it should be enabled by default
  • Set allowJs false
  • Enable forceConsistentCasingInFileNames

Key Blog posts, tweets, sites

Avoid Enums

Prefer string literal types or const objects over enums. String literal types video

  • Enums bloat the bundle because they generate a reverse mapping from the enum values to the enum names.
  • Enums cause confusion because they're the one TS feature that manifests at runtime and uses nominal typing instead of structural typing.

d.ts files

  • Only use d.TS files for js files. Avoid otherwise, since doing so creates a global type.
  • Set skipLibCheck true to improve perf. Shouldn’t need anyway. 

Handling Boundaries

Boundaries:
-Local storage
-User input
-Network
-Config-based or Conventions
-File system
-Database requests

Ways to handle boundaries

  1. Write type guards/type assertion functions. To avoid having to write type guards by hand, Zod, Valibot, tiny-invariant, typia, and many others.
  2. Use tools that generate types. GraphQL CodeGen, Prisma, Open API, tRPC
  3. Inform TS of your convention/configuration - Tanstack Router

Convert a large existing project from JS to TS via a script:

https://github.com/airbnb/ts-migrate

Cheat sheets

Utility libraries

Pattern matching via ts-pattern
type-fest
ts-extras
tiny-invariant - Throw an error if something unexpected occurs.

TypeScript with Node

  1. bun.sh - fastest, but still experimental
  2. With esbuild: esbuild-runner, tsup, esbuild-register, tsm.
  3. With swc: ts-node with swc - About as fast as esbuild, but a little more boilerplate to setup.
  4. ts-node-dev - Same as ts-node, but restarts faster

Boilerplates:
swc with Node boilerplate
https://github.com/reconbot/typescript-library-template

Generators for mocking/ testing

Books

Websites / Repos

https://github.com/mdevils/typescript-exercises

TypeScript Tips

Validate children

const allowedChildren = ["string", "span", "em", "b", "i", "strong"];

  function isSupportedElement(child: React.ReactElement) {
    return (
      allowedChildren.some((c) => c === child.type) || ReactIs.isFragment(child)
    );
  }

  // Only certain child elements are accepted. Recursively check child elements to assure all elements are supported.
  function validateChildren(children: React.ReactNode) {
    return React.Children.map(children, (child) => {
      if (!React.isValidElement(child)) return child;

      const elementChild: React.ReactElement = child;
      if (child.props.children) validateChildren(elementChild.props.children);

      if (!isSupportedElement(elementChild)) {
        throw new Error(
          `Children of type ${
            child.type
          } aren't permitted. Only the following child elements are allowed in Inline Alert: ${allowedChildren.join(
            ", "
          )}`
        );
      }
      return elementChild;
    });
  }

Map JSON strings to native JavaScript dates

Type your data as close to the source as possible, or better yet, use Zod to validate if on the server (Zod is a bit heavy for the client). Zod is especially helpful for validating and Zod schemas can easily be converted into TS types via infer. My Sandbox with a Zod format function

Strongly type env vars using Zod. And use types to disable process.env

React's ref has 2 types: React.ObjectRef (which has a current prop, and is normally what you'll want), and React.RefCallback which is for callback functions. The shorter, React.Ref is the broader type that covers both, so that's rarely useful.

Prefer unknown over any. How to read: unknown is I don’t know. any is I don’t care. So we should favor saying “I don’t know”, rather than “I don’t care”. Because “I don’t know” means, when you work with this, you need to narrow the type.

Why I don't use React.FC

"Extend" without an interface using an intersection type. But AVOID THIS because it's slow:

export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  /** Adds a class to the root element of the component */
  className?: string;
}

Strongly typed keys via Object.keys

// Helper to get strongly typed keys from object via https://stackoverflow.com/questions/52856496/typescript-object-keys-return-string
const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>;

Default Props and destructuring

type LoginMsgProps = {
  name?: string;
};

function LoginMsg({ name = "Guest" }: LoginMsgProps) {
  return <p>Logged in as {name}</p>;
}

WithChildren helper type:

type WithChildren<T = {}> = 
  T & { children?: React.ReactNode };

type CardProps = WithChildren<{
  title: string;
}>;

Clone React.ReactNode

function getIcon() {
  if (React.isValidElement(icon)) {
    React.cloneElement(icon, { className: "extra-class"});
  }
}

Support spreading props or using a computed property

[x: string]: any;

Use a type to declare a union type

Given a type like this

export const icons = {
  arrowDown: {
    label: "Down Arrow",
    data() {
      return <path ... />
    }
  },

  arrowLeft: {
    label: "Left Arrow",
    data() {
      return <path ... />
    }
  },

  ...
}

You can declare a type like this:

export type IconName = keyof typeof icons

Think of this as "whenever something has the type "IconName", it must be a string that matches one of the keys of the icons object." More on why this works.

Declare a prop on a native HTML element as required

First, create a helper:

type MakeRequired<T, K extends keyof T> = Omit<T, K> &
  Required<{ [P in K]: T[P] }>;

Then, use it:

type ImgProps 
  = MakeRequired<
    JSX.IntrinsicElements["img"], 
    "alt" | "src"
  >;

export function Img({ alt, ...allProps }: ImgProps) {
  return <img alt={alt} {...allProps} />;
}

const zz = <Img alt="..." src="..." />;

Remove a prop and declare it differently

type ControlledProps =
  Omit<JSX.IntrinsicElements["input"], "value"> & {
    value?: string;
  };

Spread attributes to HTML elements

type ButtonProps = JSX.IntrinsicElements["button"];

function Button({ ...allProps }: ButtonProps) {
  return <button {...allProps} />;
}

Omit a type

type ButtonProps =
  Omit<JSX.IntrinsicElements["button"], "type">;

function Button({ ...allProps }: ButtonProps) {
  return <button type="button" {...allProps} />;
}

// 💥 This breaks, as we omitted type
const z = <Button type="button">Hi</Button>; 

Conditional React Props (Use TS to only allow specific combinations of related props) - And an excellent video

interface CommonProps {
  children: React.ReactNode

  // ...other props that always exist
}

type TruncateProps =
  | { truncate?: false; showExpanded?: never }
  | { truncate: true; showExpanded?: boolean }

type Props = CommonProps & TruncateProps

const Text = ({ children, showExpanded, truncate }: Props) => {
  // Both truncate & showExpanded will be of
  // the type `boolean | undefined`
}

Single onChange handler

  const onUserChange = <P extends keyof User>(prop: P, value: User[P]) => {
    setUser({ ...user, [prop]: value });
  };

Derive array from union

const list = ['a', 'b', 'c'] as const; 
type NeededUnionType = typeof list[number]; // 'a'|'b'|'c';

Testing via Jest

Test utils:

// IMPORTANT: Import this file BEFORE the thing you want to mock.
import * as fetchModule from "node-fetch";

jest.mock("node-fetch");
const fetchModuleDefault = fetchModule.default as unknown as jest.Mock<any>;

// Disables console logging. Useful for tests that call
// code that outputs to the console, so we don't litter the test
// output with needless console statements.
export function disableConsoleLog() {
  jest.spyOn(console, "warn").mockImplementation();
  jest.spyOn(console, "info").mockImplementation();
  jest.spyOn(console, "log").mockImplementation();
  jest.spyOn(console, "error").mockImplementation();
}

beforeEach(() => {
  fetchModuleDefault.mockClear();
});

afterEach(() => {
  jest.restoreAllMocks();
});

// Useful for complete control
export const mockFetch = (fn: any = () => null) => {
  fetchModuleDefault.mockImplementation(jest.fn(fn));
  return fetchModuleDefault;
};

type MockFetchResponse = {
  responseJson?: any;
  status?: number;
};

// Convenient when you just want to specify the response
export const mockFetchResponse = ({
  responseJson = "",
  status = 200,
}: MockFetchResponse) => {
  return mockFetch(async () => ({
    ok: status >= 200 && status < 300,
    status,
    json: async () => responseJson,
  }));
};

// Via https://instil.co/blog/typescript-testing-tips-mocking-functions-with-jest/
export function mockFunction<T extends (...args: any[]) => any>(
  fn: T
): jest.MockedFunction<T> {
  return fn as jest.MockedFunction<T>;
}

Template literal types - Useful when you want to use a template string with some placeholders to declare a union of string literal types. Yes, you could generate the list manually (and you should if the list is huge), but this can be handy when the size is reasonable.

Advanced TypeScript

The pivotal moment of transitioning from intermediate to advanced TypeScript was realizing the type system is a programming language in itself, w/ variables, functions, conditionals, & loops. Utility types like Required, Record, Pick, Omit are all built with these primitives.

Generics parameterize types like functions parameterize value. Generics overview from Matt

Screen Shot 2022-09-01 at 8 11 50 AM

This table is a summary of Type Programming

Operation JS TS
Variable var/const Generic
Conditional == Conditional types - extends with ternary
List Array Union Types
Prop access obj.prop or obj["prop"] type["prop"]
Map obj.map [K in keyof T]
Filter obj.filter as with never
Pattern matching regex infer
Loops forEach, recursion, map recursively call type

Styling

Tech

  • CSS
  • Sass/Less
  • Inline styles
    • Automatically encapsulated
    • Use sparingly. Primarily for dynamic styles.
    • camelCased instead of snake-case
    • pixel size is inferred
  • CSS Modules
  • CSS Blocks
  • CSS in JS
  • CSS location: Separate file with component, centralize, or embed in component?
  • Namespace
  • Prefixed class names
  • Naming scheme
  • Offer unstyled components using Barrels?
  • Theming

Utility Libraries

Approaches for joining classes

Motion / Animation

Automated Testing

My Cypress vs Playwright Benchmark

102 tests in Chrome

On Jenkins, single core:
Cypress: 4:30
Playwright: 1:58

M1 MacBook Pro (multi-core):
Cypress: 2:15
Playwright: 20 seconds!

Best Practices

Data

  • Write atomic tests. Write the data you need for each test, then remove it. Avoid using the same data for multiple tests if the data can be changed.

Principles

Programmer tests should - Approach comparison

  • Minimize programmer waiting.
  • Run reliably.
  • Predict deployability.
  • Respond to behavior changes.
  • Not respond to structure changes.
  • Be cheap to write.
  • Be cheap to read.
  • Be cheap to change.

More general advice

  • Test both black box (purely on specs) and white box (look at the implementation and let that inform the tests you write). White-box-testing can improve test coverage, by better testing edge cases. 
  • Mindset: "This is so important, that we have to build an automated test suite for it. I don’t trust human testers to do the job."
  • Automated tests minimize faulty assumptions. They're a safety net for refactors later when the programmer doesn't know about all the previous assumptions and verbally communicated requirements.
  • Store related things together. So keep tests alongside the system under test.

"Write tests. Not too many. Mostly integration." - Guillermo Rauch

Automated Testing

Cypress vs Playwright differences

  • type -> fill
  • cy -> page
  • Add await
  • get -> locator
  • it -> test
  • cy.viewport ->
  • cy.scrollIntoView -> Playwright does automatically
  • Testing lib queries have shorter names on Playwright, and getBy* doesn’t assert by default.
  • (should.not.exist) -> tohavecount(0)
  • In Playwright, search in section by chaining off the parent’s locator.
  • Playwright it’s easy to forget to await.
  • describe vs test.describe

General Structure and Practices

React libraries

Testing Library Tips

Cypress Tips

More broadly, don't use the UI to build up state for each test. Instead, set it.

For example, don't actually run real login for each step. Instead, simulate it:
image

  it.only("should find 630 users when filtered by role of Salesperson or None", () => {
    cy.getByLabelText("Filter by Role")
      .click()
      .then(subject => {
        cy.getByLabelText("Salesperson", { container: subject }).click();
        cy.getByLabelText("None", { container: subject }).click();
      });
    cy.getByText("630 users");
  });

Instructions for downloading Cypress if corp network is blocking:

  1. Go to: https://download.cypress.io/desktop/4.2.0?platform=win32&arch=x64
    to download the cypress package.
  2. Copy the downloaded zip file to c:\temp
  3. Run the command (In a non powershell command line window):

set DEBUG=cypress:cli && set CYPRESS_INSTALL_BINARY=C:/temp/cypress.zip && npm install cypress
in the VSCode terminal or a cmd window

  1. Get the last cypress package run the command:
    npm i @testing-library/cypress

Cypress issues

Cypress isn't perfect.

Testing Different File Types

In browser testing / Integration Testing

Contract Testing (aka Consumer Driven Contract Testing)

Overview: https://www.linkedin.com/pulse/api-contract-testing-visual-guide-peter-thomas/
image

Test the client/server contract. Assure the API provides the expected responses, via tests. Here's why it's useful.

Tools:

Benefits:

  1. Can reveal unused interfaces - throws an error when there's unused provider code. If no apps are consuming it, obviously the code can be deleted from the provider (the API).

image

Visual Testing

Performance Testing / Monitoring

Property Based Testing

Generate valid random values and feed to tests. e.g. Pass random strings and ints to a func that accepts a string and int.

Validation Testing

https://ealush.com/vest

Mutation Testing

Change code and if it doesn't fail, that means you have holes in your test coverage.

Fuzz Testing / Randomized Testing / Test Generation (like Pex for C#, or QuickCheck which popularized the idea)

Recommended Reading

Testing React components with Jest and Enzyme
Node and JS Testing Best Practices

Redux

Redux

  • Warning: React-query is likely simpler
  • Switching from Redux to Context with Hooks
    • See Selectors in the post above for an example of using Hooks for selectors
  • Solid image-based intro
  • Why Redux?
    • Advantages over context:
    • Connected components are automatically pure
    • Performance. Selectors mean each component only re-renders when it's props or state changes. With context, all child components re-render. Switching to context can hurt performance. But keep in mind that Redux selectors (e.g. mapStateToProps) run for every component after any Redux state change, so those need to be fast. Also useSelector is a hook, so it can't stop renders caused by parent components. An app that only has useSelector everywhere should probably add React.memo() to some components to help avoid renders from cascading all the time.
    • Ecosystem (reselect, Redux form)
    • Redux devtools (time travel)
    • Middleware (log actions, intercept all actions or certain actions, replay user issues using logrocket)
    • Comparisons with Context:
  • Why Not?
  • Actions
  • Action creators
  • Action constants
  • Store
  • Reducers
  • Immutable data structure approaches and in Redux docs
    • immutableStateInvariant
  • Connect via HOC
  • Connect via Hooks
    • mapStateToProps -> useSelector
    • mapDispatchToProps -> useDispatch - Note, useCallback if you want to pass dispatch down to child components and are worried about re-renders. dispatch gets a new instance on each render so child components will needlessly re-render when the parent re-renders otherwise. This is a downside over connect.
    • How useSelector differs from mapStateToProps in connect
      • Can return any data structure from useSelector, not just an obj like in mapStateToProps.
      • Can call useSelector multiple times. Multiple calls are batched into a single render.
      • No ownProps, but instead can be accessed since useSelector is declared inside component.
      • Does a strict equality check instead of shallow comparison. So watch out, returning a new object from useSelector will always result in a re-render. To avoid the needless re-render you can:
        • Call useSelector multiple times so that each one doesn't instantiate a new obj inside.
        • Use reselect to memoize
        • Override the default equality check using shallowEqual from react-redux
      • Connect avoids child components re-rendering when their parent changes if their props don't change. useSelector doesn't do this. So useMemo on the child if you have a perf concern.
  • Testing
  • Ducks
  • Selectors / Reselect

Redux Best Practices

  • Keep actions lean. They should merely describe an action. It's the reducer's job to actually handle state changes.
  • Keep each reducer's state shallow. For example for an e-commerce application, instead of having a cart reducer with cartItems in addition to coupon codes, have a cartItems reducer to manage that slice of your application state and a couponCodes reducer to manage that part of your state.
  • Think of your Redux store like a normalized DB. Avoid creating an action and reducer for each container. This leads to needless boilerplate and reduces Redux's power. Instead, container, actions and reducers should be decoupled. One action can be handled by multiple reducers. Multiple reducers can handle a single action. More here from Dan.

Redux Thunks

Redux Saga

  • Slides
  • Generators
  • Effects
  • Helpers

Maintainability

Performance

  • Use selectors for Redux
  • Normalize your Redux store
  • Structure your Redux store by key for fast access

React Fundamentals

React Fundamentals

JSX

State

  • It's async. setState calls are batched. Why? No matter how many setState() calls in how many components you do inside a React event handler, they will produce only a single re-render at the end of the event. This is crucial for good performance in large applications because if Child and Parent each call setState() when handling a click event, you don't want to re-render the Child twice.
  • An example of state being async. Note that alert shows value that was "closed over" when the button was clicked, not the current value in state.
  • To avoid needless re-renders, avoid calling setState when data hasn't changed (or use shouldComponentUpdate)
  • Approaches for handling state in an immutable manner (or use Immer)
  • Accepts object or function. Functional setState receives prevState and props as params.
  • Accepts callback as 2nd param (but recommended to use componentDidUpdate instead)
  • Why treat state immutable?
  • Tips for using state correctly
  • Four immutable approaches
  • Where to put React state (flowchart)

Forms

Functional components

Class Components

Typechecking

Props

Keys

Hooks

useReducer tips: (below are from redux's style guide, but relevant)

useEffect Best practices

  • tkdodo Tips for simplifying useEffect
  • useEffect is taught too much / too early. It's much more important to teach ways to avoid useEffect: derived state, single source of truth for state, react keys, callback refs, useSyncExternalStore even... know about them and you likely will not need useEffect.
  • WARNING: Almost none of the effects I see in app codebases are syncing with something outside of React. It's always: if prop change, update state, if state changes, dispatch another action, or if state changes, compute something and put in another state. All of these are bad.

Component Composition

Error handling

Best practices

Quiz

  1. How does JSX differ from HTML?
  2. Is JSX required?
  3. What tool compiles JSX?
  4. What method is required on all class components?
  5. What is a lifecycle method? Can you name one?
  6. What is destructuring? Why do we do it? Contrast object destructuring with array destructuring.
  7. Why prefer const/let over var?
  8. What tool did we use to create our React app?
  9. What Hooks did we use? What were they for?
  10. Do lifecycle methods exist in function components?
  11. What tool is checking our code quality/standards and checking our code for common errors and issues?
  12. How do we declare data that changes over time?
  13. What’s the term for passing config settings into a component?
  14. How do we declare what values our component accepts?
  15. When do you declare a key? Why declare a key? What’s a good key? What’s a bad key?
  16. How do you run an npm script?
  17. Why is client-side routing preferable to server-side?
  18. How do you make a function public?
  19. How do arrow functions differ from regular functions?
  20. How do you copy an object in JS? Is it deep or shallow?
  21. When does React re-render?
  22. How do you declare state in a class? A function?
  23. What tool are we using to automatically format our code?
  24. What does JSX compile down to?
  25. What tool are we using for our mock API? How did we configure it?
  26. How did we automate starting our app and API at the same time?
  27. What array method did we use to iterate over the list of users? What does it return?
  28. What is a predicate?
  29. What is a higher order function? List some higher order functions on the array prototype.
  30. How do you copy an object in JS? Is it deep, or shallow?
  31. What is a wildcard import? When is it useful?
  32. What are the benefits and downsides of using a default export?
  33. Does const make an object immutable?
  34. Name 2 ways to declare a React component. Which should you prefer?
  35. What is the current version of JS? How often are new versions released?
  36. When is the rest operator useful?
  37. What’s the name for arguments passed to React components?
  38. How do we specify the types for each argument?
  39. How did we debug?
  40. What hook did we use to run code after render?
  41. What’s a promise? How do we handle a successful promise?
  42. How do we handle an error from a promise?
  43. When you copy an object in JS, is it deep or shallow? What’s the difference?
  44. Why is client-side routing preferable to server-side?
  45. Is the code we see in the browser what’s actually running?

Pre-event checklist

  • Assure room has power for all.
  • Request a TA. Helps keep things rolling.
  • Have a chat window that TA monitors. Can ping me as needed.

Reveal Management Solutions Agenda

1/28 - 1/29
9am - 4:30pm

Session Intro

Advanced React – Explore lifting state, containers, presentation components, extracting state, conditional rendering, formatting/styling components, binding approaches, extracting child to avoid bind, compound components, branch pattern, controllable components, deep cloning, avoiding self-referential state, setState callbacks, state initialization patterns, higher order components, render props, centralized form change handling, and more.

Automated testing – Begin with an untested example application and explore testing approaches by methodically adding automated unit and integration tests using Jest, Enzyme, react-testing-library, and/or Cypress. 



Centralized state management via Redux – Explore actions, reducers, async middleware like thunks/sagas, action constants, store configuration, react-redux, selectors, and so on. Enhance an existing application to utilize Redux for state management. Explore when Redux adds value, common pitfalls, and establish standards for internal usage.

Reusable React Components – Explore patterns, principles, and technologies for designing, creating and publishing reusable React components. Learn how to share React components as npm packages so you don’t have to copy/paste useful React components between projects. Create interactive, automatically generated documentation and a style guide so your developers can easily reuse components. 


Creating Reusable API proxies – Learn how to encapsulate your web APIs in npm packages for easy reuse across projects.

Custom React development framework – Design and implement a standardized approach to React development for use at your company. This approach programmatically enforces consistency, speeds code reviews, fosters cross-team collaboration, eases ongoing maintenance, centralizes bug fixes, and avoids ongoing decision and reimplementation overhead.

Code review - Review existing project code to establish opportunities for improvement. Review technical and architectural decisions, dependencies, production application bundle, development workflow, and more.

Recommended Resources / Next steps

athenahealth Agenda

Wednesday (9/18)

9 AM – 10 AM: Consulting – Consumer Health (Consumer Forge Discussion)
10 AM – Noon: Consulting – Scheduling (Front End Review)
Noon – 1 PM: Lunch Break
1 PM – 4:30 PM: Lecture – Responsive Web Training Part 1 (details below)

Thursday (9/19)

9 AM – 11 AM: Lecture – Responsive Web Training Part 2
11 AM – 12:30 PM: Consulting – Consumer Health (Portal 2.0 Web Review)
12:30 PM – 1 PM: Lunch Break
1 PM – 3 PM: Lecture – Web Accessibility

Advanced React

Note: I deliberately leave many of the topics below out of fundamentals.

React top level api: https://reactjs.org/docs/react-api.html

Upcoming "use" hook

Primitive for handling asynchrony.
Works like “await” inside non-async client-side components.
Wrap promises (and soon other things like context) with “use”.
If a promise passed to use isn’t resolved, “use” suspends the component’s execution by throwing an exception. The component replays when the promise resolves.
A “usable” type is a wrapper for a value. Calling “use” unwraps it.
Only for client (like most hooks).
Async server components use plain async/await.
Only non-async server components can use hooks.
Unlike other hooks, can be called conditionally. Why? Because the data lives in the promise object itself. So there’s no need to store state for “use” across updates.
Can be placed in the same spots as “await” including blocks, switch statements, and loops.
Part of the “Data fetching with Suspense” story.

UI Architect / Frontend Architect / FrontendOps /
ops - Responsibilities:

State management / Finite State Machines / Statecharts
Reusable components, scripts, styles
Design system / Style Guide (collaboration)
Dev environment (transpiling/bundling/linting...) and dev tools
Build automation
Mock APIs
Automated testing (unit/integration/visual)
App composition/slicing
Error handling
Event Modeling
Accessibility
Performance
Security
Dev tools
Dependency management
More here and here

Signs it's time to consider extracting a new component

  • Duplicated JSX (extract to the same file if not reused elsewhere) - see #8 here
  • Reuse
  • JSX gets difficult to read
  • To allow thinking about page sections in isolation (each component becomes a black box, which reduces cognitive load)
  • Props list gets long
  • Document different states in Storybook, create dedicated image tests with Chromatic/Percy/etc
  • API calls and JSX in same component - Extracting API concerns means you can feed mock data via props
  • Performance (extract an expensive portion so you can optimize its rendering)
  • To keep style selectors short (whether it be BEM or CSS Modules, smaller components = smaller namespace = can use nice short names and easily navigate). If you find yourself prefixing selectors by section like this, consider extracting a component.
  • To divide work between people/teams

Why prefer fewer components?

  • Less jumping between files
  • Minimize prop drilling and propType declaration overhead
  • Shallow trees may be easier to understand than a deeply nested tree
  • Every new file adds a little bloat to the bundle due to Webpack's bundling overhead

So it's a tradeoff.

Useful middle ground here: You can declare multiple components in a single file, but export only the "parent". This avoids jumping between files and provides a clear public API. If you prefer separate files, you can create a component folder and place all its child components in that folder, then use a barrel to export only the Header.

Brain Teaser

Why doesn't the onSubmit fire here?

Patterns for scaling

Advanced Hooks

  • useReducer - Alternative to useState. Easily test in isolation. Move state logic from component to separate file. Useful to avoid having many useState declarations and multiple calls to setState in a row. Also preferable when next state depends on the previous state (though callback form of useState also helps there). Also a valid alternative to useCallback because you can pass dispatch down instead of callback funcs. Dispatch identity is stable - it doesn't change over renders.
  • useCallback - Memoize a func so that children get the same reference with each render. Useful when children are expensive to render and thus need to avoid needless re-renders due to function props changing. In other words, child components that use React.memo, shouldComponentUpdate, or PureComponent to avoid re-renders benefit from having a parent that uses useCallback to avoid needlessly sending down a new func reference on each render.
    • Tip: Struggling with useCallback dependencies causing it to be reallocated? Pass arguments to the function instead so that it has no dependencies.
  • useMemo - Memoize an expensive value to avoid re-calculation on every render.
  • useRef - Create a reference to a DOM element or hold a value that isn't rendered
  • useImperativeHandle - Combine with useRef. Use to customize the value provided by ref. Allows parent to call arbitrary functions in child. For example, focus child's component's input. demo
  • useLayoutEffect - useEffect runs after render. This runs before render. Useful when you want to calculate position before rendering.
  • useDebugValue - Apply to custom hooks you share in a library so they have a useful label in devTools.

Example Custom Hooks

JSX in Depth

Key Advanced Features

Context

Refs

  • Think of refs on React elements as functions that are called after the component has rendered
  • Use useCallback with a ref to run some logic when the ref's target changes. useCallbackRef example)
  • React docs
  • Prone to abuse. Avoid - you may not need it. Can be misused to manually change the DOM.
  • 3 common valid uses:
    • 1. Read and change DOM: focus, and calculate size and position.
    • 2. Hold values not used in render in func components (can use instance vars in classes).
    • 3. Forward refs to leaf nodes to support programmatically setting focus on elements. Useful for alerts, dialogs, textInputs. This way when something new appears/changes, you can programmatically focus the element.
  • Detailed blog post "The Complete Guide to React Refs"
    • Refs are basically a special case of useState that doesn't trigger a re-render
    • Set its value directly (instead of using a setter) via myRef.current = 'val here'
    • Get value via .current property: myRef.current
    • 4 approaches - cheatsheet:
      • String refs (deprecated)
      • Callback refs (clunkier syntax than createRef, but can be preferable when dealing with dynamic refs - otherwise prefer createRef or useRef below)
      • createRef (Classes only - simpler syntax than callbacks)
      • useRef (Funcs only) UseRef is basically this

Other Advanced Features

State

Props

Performance

Old alternatives to React.lazy:

Forms

I recommend plain React. Here's a poll. But, many options. A few popular options:

Maintainability

Debugging

Server Rendering

Deployment

  • If users leave their tab open for days/weeks, they may request an old file when they click a link. Avoid users getting errors by requesting an old file that's no longer deployed by including the site version in a cookie. Use that to say "A new version of the site is available. Click OK to reload the site." as suggested by Rich Harris.

More?

  • Show and tell! What patterns have you found useful?

Remix

Special functions - export a func with these names and they'll get called by Remix:

  1. loader - Returns server data. Make API calls here
  2. action - Handles posted form data. Has same API as loader, but responds to POST, PUT, PATCH, DELETE calls, unlike loader which responds to GET calls.
  3. meta - Sets HTML meta tags
  4. headers - Set headers
  5. links - Creates link tags in head (for CSS, favicon, preloaded images)
  6. Default export is the layout that renders the rest of your app in an Outlet
  7. Export optional ErrorBoundary - Renders when there's an uncaught error anywhere on the route, (during render of data loading, including loader and action). Like normal React ErrorBoundary, but receives error as prop.
  8. Export optional CatchBoundary - Like any other route component, but renders when an action/loader throws a Response, and has access to useCatch instead of useLoaderData.

Hooks

  1. useLoaderData - Returns JSON from loader
  2. useActionData - Returns JSON from action. Returns undefined if there hasn't been an action yet.

CRA differences

  1. Uses esbuild, so build is crazy fast
  2. Asks for hosting at app creation
  3. Includes server
  4. Like Next, uses npm run dev for dev, and npm start to run the build (so it's hosting friendly, since the hosted solution would call npm start)
  5. Fast build, built in Go
  6. Graceful degradation - Works without JS
  7. You get to decide what to render at the root - Just slap an html at the root of the component!
  8. CSS is automatically tied to a route, and placed in the head via Link , then displayed on a given route via Links . Result? No worries about styling clashes across pages! So no more need for CSS in JS / CSS modules! And CSS for each page is lazy loaded, using the platform!🔥
  9. Add a .server extension to instruct remix to only run the file on the server, never send it to the browser.
  10. Comes configured with ~ as a reference to /app (TypeScript's path in tsconfig is set up to honor this)
  11. Loaders basically give you a BFF for free. The queries to the DB run on the server, so they're fast, avoid a round trip, and only the data you specify is returned to the client.
  12. Export an action function to handle a form submission.
  13. Built in caching support using the platform
  14. Use Link rel="prefetch" to preload links
  15. Seamlessly share code between the client and the server - see new.tsx in jokes app for an example of how the validation functions are just plain JS functions declared in the component. So they can be leveraged on either side. But if they're not referenced on the client, they should be tree-shaken out for the client build.

Next similarities

  1. File based routes (though can use remix.config to declare routes too if preferred)
  2. Dynamic routes use $slug instead of [slug]

Remix advantages over Next

  1. Fetching and displaying data requires significantly less code than Next.
  2. Fetches nested routes in parallel
  3. Easy to upgrade to if you're using React Router 6.4 already
  4. Uses useLoaderData instead of injecting props via getServerSideProps - Example
  5. Embraces progressive enhancement. Remix works without JS by default. Forms and links still work without JS. So Remix degrades gracefully without JS (which we know can happen for various reasons. Next has a feature to optionally remove only the framework's JS runtime (not all JS), but it's been experimental for over a year. More.
  6. Embraces web standards. Learning Remix is basically learning web standards. Uses browser's Response type.
  7. Styles are automatically scoped to the page, since they're only loaded for the page. No need for special tech like CSS modules.
  8. Export links object to add links (like stylesheet references) to the head.
  9. The component contains its API route via loader, which runs on the server, but is declared inside the component. This makes type safety easy. Think of Remix routes as backend views using React for templating, but then they know how to seamlessly hydrate in the browser to add some flair.
  10. Export actionFunction in the same file to handle server POSTs. Can omit the action on the form since it posts to the same page by default. Result: Less file hopping, less config, and simpler mental model.
  11. Includes json function for easily returning json from an ActionFunction
  12. Includes redirect func which can be run on the server to fire a redirect.

Next advantages over Remix

  1. Vercel is a larger, more established startup with more VC funding
  2. React Server components support
  3. Next includes a smart Image component (Remix claims theirs is coming soon)
  4. Next supports static pre-compiled pages
  5. Has fewer package deps, so package.json is more concise
  6. Intelligently prefetches links. With Remix, you opt-in via the platform: Link rel="prefetch"
  7. Better error messages - Remix errors sometimes don't mention the component where the error is being thrown. So gotta comment things out to hunt issues down 👎

Utils

https://github.com/sergiodxa/remix-utils
https://github.com/brophdawg11/remix-validity-state

Typing Remix

https://www.epicweb.dev/fully-typed-web-apps

React App Review Checklist

This outlines a list of items I look for when reviewing a React app.

Foundation: Framework / Generator / Boilerplate / Package management

  • Using the ideal framework for the use case: cra, Next, Remix, Gatsby, etc.
  • npm, Yarn, pnpm
  • TypeScript

A11y

General State

Context

  • Context is centralized and abstracted
  • Context is split
  • Context is applied to the lowest subtree
  • Context use is justified and minimal - not merely used to avoid passing props a couple levels

Hooks

  • Repeated logic is abstracted and centralized via Hooks

Performance

To reduce renders:

  • Split components
  • Pass only the necessary data
  • Pass children down (reduces prop-drilling too)
  • Lazy load

Reusable components

  • Documented via Storybook and ZeroHeight, or custom docs in react-docgen
    • Props with JSDoc comments above each
    • Component use cases
    • Import statement
    • Demos
    • Do's and Don'ts
    • A11y concerns
  • Mutually exclusive props are impossible
  • Prefer false defaults (since prop existence conveys truth)

Dev workflow

  • Calling stable, local mock APIs
  • Custom dev tools
  • Build initially in Storybook
  • Cypress-driven development

Testing

  • Using Jest with testing-library and Cypress with testing-library
  • Comprehensive Unit and Integration tests
  • Reliable E2E tests (via a test db if you own the stack e2e, or via high level "smoke tests" if you're calling APIs your team doesn't own)
  • Use Storybook stories in unit tests

Other topics

Playwright - Test in the browser
ESLint - Check code quality and errors for safe React development
Storybook 
Reusable component / how to comment
Add fields (select/dropdown, field types)
Add search / filter projects
Add login / Global data via context or alternatives
State management best practices
Styling - CSS modules and Tailwind
Dropdown for project manager 
Reusable component design
Custom hooks
Clean up types, organize types, and use utility types
Review 55 lessons doc 
Data fetching
Caching
Routing (React Router 6.4 loaders, etc too) 
Layout component 
Review issues
Custom dev tools
useReducer and tests
Login with Context

Reusable React Components

Reusable React Components

My Course - Building Reusable React Components

Lessons Learned Building a React Component Library in Typescript blog post

Consider multiple abstraction levels - May make sense to implement simple standalone components and then compose them in opinionated ways. Consider offering both low and high level abstractions, as inspired by the visualization libraries post above.

Rigid vs Flexible tradeoffs:

Rigid benefits:

  • Enforces consistency
  • Encourages teams to reach out so we can systematize customizations by adding props
  • Fewer props = simpler, but can lead to proliferation of props if we keep adding ad-hoc props for styling.
  • Less duplication risk
  • Can programmatically enforce best-practices such as accessibility
  • Building each component takes longer, since we have to carefully try to cover all scenarios

Flexible benefits:

  • Favors developer autonomy and initial dev speed. Less need to wait for a new component library release to get what you need.
  • Encourages use. If it's not flexible enough, people just won't use, or will create ugly hacks based on implementation details.
  • The APIs and styles need not be perfect. Can be more freewheeling.
  • Developers may rely upon classnames to customize, making DOM changes in the component library risky

Broadly, choose an abstraction level, or perhaps multiple.

Choosing a CSS abstraction level via customization-vs-configuration-in-evolving-design-systems
image

Questions

  • Have you created any reusable components yet?
  • How are you handling reused components within a single project?
  • Open to considering monorepo?
  • Specific components in mind?

Storybook Tips

  • Skip HTTP for mock APIs. Instead, develop mock API that return Promises.
  • Use setTimeout to fake 1 second delay so preloaders show
  • Use the same mock data as you use for tests and driving the app's mock API.
  • Document all the potential states listed below.
  • Place stories alongside the component so they're easier to find, open
  • Consider knobs, info plugins

Picking a Third Party Library

Headless component libraries

If you have a specific design system from your designer, it might be easier and better solution to go with headless components that come unstyled than to adapt a fully featured library's components to your needs. These tools solve the most important accessibility challenges while remaining totally agnostic when it comes to cosmetics and styles:

Reakit - Focused on a11y
Chakra UI - Okay, it has some styles, but listing here since it basically has some lightly styled defaults
Reach UI
Headless UI
Radix UI
react-aria
MUI Base
Lexical - headless editor from Meta, alternatives: Slate, Tiptop
Tanstack Table, TanStack Virtual (similar to react-virtualized, react-window)
Downshift
Riakit / AriaKit
TailwindUI
cmdk
FloatingUI
React dnd-kit
Formik, React Hook Form
https://react-hot-toast.com/
Many more options and context in this slidedeck

Lexical - Rich text editor (WYSIWYG)

How to choose between the libraries above:

  • Library ecosystem
  • Accessibility
  • Have a corp style guide? Need to match existing design?
  • What sorts of components do you envision yourself needing?
  • Styling approach? Need to consume styles outside of React?
  • Documentation
  • Browser support
  • Open issues
  • Consider grabbing a few off the shelf like a datepicker, then build the rest.

Potential Component States

A handy checklist to consider. Typically, it's useful to have a dedicated storybook story for each applicable state below.

  1. Disabled
  2. Initial state (before any interaction on the screen - sometimes just renders empty)
  3. Responsive design
  4. Validation error
  5. No data
  6. Focused
  7. Hover
  8. Lack of permissions
  9. Data changed / pristine / not persisted
  10. Loading state (spinner / skeleton / no render / progress bar...)
  11. Slow connection (consider displaying a "Keep waiting?" message)
  12. Loading timed out - Can also consider a fallback state that displays cached data and a button to retry. Example: A todo's list component fails to load, so you display the todos that were stored in localStorage. The user also sees the message: "The latest data failed to load. Click here to try again."
  13. Action timed out - Example: A save failed. Keep users data on the screen and display a message "Sorry, save failed. Click save to try again."
  14. API call error
  15. Offline - One could be offline, but still be able to write if the component writes to localStorage. Though it's helpful to tell the user their data is being temporarily stored locally until a network connection exists.
  16. Read only
  17. Using a screenreader
  18. Consider and test for different permutations of props

Related tweets here and here

Core Decisions

Dev Environment

Documentation

Sandbox / playground / live editing

https://github.com/nihgwu/react-runner
https://github.com/FormidableLabs/react-live
https://github.com/codesandbox/sandpack
Tweet

Design

States - When a user is interacting with a component, what are the different states the entire component or its parts can go through? Common states include:

  • Hover - The mouse is over the component. Keep in mind this state will never be seen in mobile.
  • Focus - The component has cursor focus, so typing will affect this component.
  • Active/Pressed - Usually only visible briefly e.g while the mouse button is pressed.
  • Selected - Mainly applies to lists or toggle-able elements.
  • Disabled - The user can't interact with it currently even though it usually is an interactive component.
  • During dragging - We haven't figured out a general approach here yet.
  • Error states - Do errors apply to this component? Does it need to catch the user's attention for a critical or patient safety issue?

Content - What is the range of content that a component can take?

  • Text - Is it only text or can it be anything?
  • Size - How small or big can it get?
  • Truncation - If we set a size limit, how do we truncate and indicate to the user that there's content they can't see?

Surroundings - What are the different surroundings a component is likely to be used in and do they affect the design? Common relevant contexts include:

  • Darker background - Do the component colors need to change?
  • Limited space (or very large space) - how does the component accommodate space limitations
  • Mobile - No hover states or cursor in addition to smaller size (not considering much now, but should start)
  • Co-location - Is this component's relationship to another piece of the UI especially important? If so, what are the variations of that other component to consider?

Animation - When changing states or content, what do the transitions look like?

  • Layout - Layout transitions like height and width are especially tricky and can impact the work needed to implement.
  • Speed - Preference for fast or slow? Often this is based on size.

More Design Concerns

  • Make impossible states impossible. Group related props into an object.
  • Declare contain CSS to improve rendering performance
  • Atomic Design
    • Atoms
    • Molecules
    • Organisms
  • Keep booleans positive
  • Extend HTML base element's props and pass them to the root - And consider the tradeoffs in different approaches to doing so
  • Honor native API. Accept native HTML props and pass them down to the underlying element. Avoid creating a new API that doesn't honor the plain HTML element.
  • Prefer false defaults to shorten JSX
  • Avoid the boolean trap - Avoid using booleans that may conflict. Instead, accept an "enum" for mutually exclusive options. Example, accept a buttonType prop with a list of potential string values like primary, secondary, etc, rather than isPrimary, isSecondary.
  • Watch out for bool props - might be a sign you need an enum. Might also be a sign two separate components would be preferable (much like funcs)
  • Create a BaseProvider for things like themes, i11n, LTR
  • Internationalization (i11n) - Nice example from Uber's base UI
  • Support "addons" props for TextInput, etc. addons: [{ element: <MyElement/>, position: POSITION.AFTER_INPUT}] or simply belowAddons: <MyElement>.
  • Different approaches: Accept child components or strings for things like headers on tabs or styled <H1> - <H5> components. Use isValidElement to determine if string or element passed.
  • Selecting an audience
  • Be consistent. Example: If you're prepending boolean property names with is or has in one place, do so consistently.
  • Allow caller to declare the top-level DOM element that will be rendered - For example, use or
    instead of
  • Export an enum for a finite set of props so the consumer can import the enum along with the component and use it, and use the enum in propType declaration for oneOf
  • Wrap HTML primitives?
    • Don't rename HTML attributes. Never override HTML attributes in your components. A great example is the element's type attribute. It can be submit (the default), button or reset. However, a lot of developers tend to re-purpose this prop name to mean the visual type of button (primary, cta and so on). By repurposing this prop, you have to add another override to set the actual type attribute, and it only leads to confusion, doubt and sore users.
    • Whenever your component is passing a prop in your implementation, like a class name or an onClick handler, make sure the external consumer can do the same thing. How:
  • Use props.children for more flexibility, and consider creating named "slots" if a single child isn't sufficient. Names slots are useful when the component allows the user to place arbitrary content in multiple spots (such as a card component with different named sections, or a pagelayout component with named header, body and footer slots.
  • Consider accepting an "as" prop to declare the top level element type
  • Folder structure
  • Declare propTypes and be specific. Start required. Loosen as needed.
  • Set useful defaults so users can pass fewer props. Plus, you need not check within the component
  • Apply custom props?
  • Defaults?
  • Accessibility
  • Server rendering
  • Config object vs. primitives
  • The orchestration pattern
  • Compound components using context. Also a simple tabs example
  • Only allow certain prop types - This forbids using certain child elements by validating each child element tag
  • More here - The 10 component commandments

Mobile

Mobile friendly component options:

  1. Responsive design, so no mobile-specific features. Example: BottomSlidePanel
  2. Built-in media query - Examples: IconButton, Accordion, Table. Advantage: Easy. Disadvantage: Not configurable. Compromise: Include mobileMaxWidth or isMobile prop.
  3. isMobile prop - isMobile prop - Consumer must set it. Downside: Extra work that people will likely forget. And prop name doesn’t specify what this does. Gotta check the docs. And if the consumer wants only some of the mobile features, they can’t specify. It’s all or nothing. Advantage: Could use this same convention for any components, if we can accept the caveats.
  4. mobileMaxWidth prop - mobileMaxWidth - Advantage: Slightly better than previous option since consumer doesn’t have to read the width to determine when the mobile features should kick in. Disadvantage: All the same as previous.
  5. Well-named prop that describes the specific behavior. Advantage: Can use certain features. Disadvantage: User must wire it up and read the screen width. Example: Avatar. Table density. 
  6. Separate mobile component - Advantage: Can lazy load, or not use at all if not relevant. Avoids bloating bundle or slowing loads. And can use on desktop too if relevant (for better or worse). But more work to weave, and many won’t bother. Example: https://material-ui.com/components/steppers/#mobile-stepper

Styling

  • See Styling list

Testing

  • Framework
  • Assertions
  • Helpers
  • Unit
  • Interaction
  • Structural
  • Style
  • When to run
  • Where to place tests
  • Continuous Integration
  • More here

Development decisions, tips, and workflow

  • Will this be maintained by a single, centralized team?
  • Open or closed source? Inner source?
  • Keeping UX and UI in sync
  • The rule of three
    • Consider standalone npm packages at first, then deprecate when pulled into central lib
    • Use nwb or better yet your own solution with more opinions
    • Consider a naming scheme or centralized documentation for standalone components to aid discovery
  • Testing changes before publish
    • Link
    • Pack
    • Beta
    • Lerna bootstrap
  • Documentation
    • Use as dev environment
    • Generate or build by hand
    • Use a boilerplate, doc tool, or build your own?

Deployment

  • npm package structure
  • Automated build
    • Exclude React/React-DOM from the build
    • CommonJS build
    • ES build
    • UMD build
  • Dependency declarations     
  • Hosting
  • Versioning - honor semver
  • Import approach
  • Declaring package files
  • Output formats
  • Pre-publish testing
  • Build process

Validate children - only allow certain types of children

const allowedChildren = ["string", "span", "em", "b", "i", "strong"];

  function isSupportedElement(child: React.ReactElement) {
    return (
      allowedChildren.some((c) => c === child.type) || ReactIs.isFragment(child)
    );
  }

  // Only certain child elements are accepted. Recursively check child elements to assure all elements are supported.
  function validateChildren(children: React.ReactNode) {
    return React.Children.map(children, (child) => {
      if (!React.isValidElement(child)) return child;

      const elementChild: React.ReactElement = child;
      if (child.props.children) validateChildren(elementChild.props.children);

      if (!isSupportedElement(elementChild)) {
        throw new Error(
          `Children of type ${
            child.type
          } aren't permitted. Only the following child elements are allowed in Inline Alert: ${allowedChildren.join(
            ", "
          )}`
        );
      }
      return elementChild;
    });
  }

  // For performance, only run during development
  if (inDev) {
    validateChildren(children);
  }

More solid tips in this blog post

Projects to add

Add genericized versions of others projects to this repo.

  • Course management app
  • Permissions (nice and general. Perhaps a good example) Especially useState vs useReducer
  • Predictament?
  • Fuel savings calculator

Next.js

Benefits over CRA

My summary of below on Twitter

  1. Faster startup (compiles pages on-the-fly)
  2. Faster builds (uses swc and Turbopack).
  3. Supports React Server components with automatic server-side caching
  4. Static generation support
  5. Server-side rendering with dynamic data via getServerSideProps. This often leads to faster loading performance since HTTP calls start earlier, and the server typically has a much faster and more reliable connection than the user's machine/phone. It also improves SEO.
  6. Strong opinions about where things go (makes it easy to switch between projects)
  7. More active development (check release notes!)
  8. Built in, file-based client-side routing. Dynamic routes via [placeholder].js syntax. Export async getStaticPaths func inside that returns an array possible id values. Also export getStaticProps to fetch necessary data.
  9. Auto code splitting by route (splits CSS modules too). So, lazy loads by default (set priority to true to eager load)
  10. Auto prefetches links
  11. Automatically rendered to avoid layout shift (Next/Image helps enforce this by requiring width and height)
  12. next/image optimizes images, even for external sources. Optimizes them on-demand instead of at build time.
  13. Prettier error page (though errors are occasionally cryptic)
  14. Built in Head component for title, favicon, meta tags (no need for Helmet)
  15. Built-in styled-jsx (but like CRA can use any CSS-in-JS lib)
  16. Integrated hosting, CI, and deployment via Vercel. Ephemeral branches: Push to any Git branch to preview, hosted. Then push to main to deploy. Slick. Like Netlify.
  17. Eliminates unused CSS
  18. Already supports React 18 server components
  19. Add files to pages/api to get a serverless API. Useful for saving form input, calling a 3rd party API, or previewing draft content.
  20. Uses Express and supports Express middleware
  21. Font optimization
  22. Built in scroll restoration

Cons

  1. Have to restart the app sometimes
  2. Occasionally cryptic error messages
  3. "Leaky" Link abstraction requires declaring href in odd ways depending on what's being wrapped. To add attributes like className, target, rel, etc to the actual anchor, must actually slap an anchor underneath: https://github.com/vercel/next-learn/blob/master/basics/snippets/link-classname-example.js
  4. File based routing leads to multiple files named index.
  5. Starting dev doesn't catch TS errors. Gotta run the page.
  6. Missing: eject, ESLint, Testing

Screen Shot 2022-11-01 at 6 51 05 PM

3 rendering strategies

  1. Static generation (generates HTML at build time). Win: Renders without JS! Pre-renders each page’s HTML, instead of via client-side JS. (So better perf and SEO). Minimal JS is included as needed (called hydration after load). To decide if this is merited, ask yourself: "Can I pre-render this page ahead of a user's request? Can even do static generation with data using getStaticProps, so data is fetched during build (from file system or HTTP). (in dev this runs on page load). See oddities below for more on getStaticProps. Pages that use Static Generation and assets (JS, CSS, images, fonts, etc) will automatically be served from the Vercel Edge Network, which is blazingly fast.
  2. Server-side rendering - Dynamically generates HTML on each request. Use when page shows frequently updated data / content changes on every request. Use getServerSideProps instead. Time to first byte (TTFB) will be slower than getStaticProps because the server must compute the result on every request, and the result cannot be cached by a CDN without extra configuration. Pages that use Server-Side Rendering and API routes automatically become isolated Serverless Functions. This allows page rendering and API requests to scale infinitely.
  3. Static get without data + fetch data client side (use for private, user-specific pages where SEO isn’t relevant - that’s a LOT of pages)

Can choose between the 3 above on each page.

NOTE: Do Not Fetch an API Route from getStaticProps or getStaticPaths (would be nonsensical because the code only runs on the server).

Easily add Tailwind (Likely true for CRA too?)
Polyfills fetch

Oddities

  1. No src dir. Instead: all folders at root: pages, components, public
  2. No index.html. To customize the tag, (for example to add the lang attribute), create a pages/_document.js file
    For global CSS, must create pages/_app.js - This component is common across all pages. Think “base page”. You cannot import global CSS anywhere else.
    getStaticProps or getServerSideProps to import external blog data into the index page.
    Can query DB directly since it only runs server-side. Code in getStaticProps isn’t even sent to client.
    Note: getStaticProps can only be exported from a page

Dev tools used behind the scenes

  • Turbopack
  • Swc
  • Babel
  • TypeScript

Conditional Rendering

if (typeof window !== 'undefined') {
  // client-side-only code
}

or, via a component: vercel/next.js#2473 (comment)

Addons

Next-runtime provides Remix-like ability to handle posts in the same file via getServerSideProps.
https://github.com/blitz-js/superjson

CSS Grid

CSS Grid

Key terms:

  • Declare a grid container, with grid items (direct descendants) inside. If it's not a direct descendant, it's not a grid item.
  • grid line - the dividing line that makes up the grid's structure. Can be vert (column grid lines) or horiz (row grid lines).
  • grid track - The columns/rows of the grid. (Space between adjacent grid lines)
  • grid cell - Like a cell in a table/spreadsheet. A single "unit" of the grid.
  • grid area - Total space surrounded by four grid lines. Can be comprised of any number of grid cells.

grid
Declare a grid container:

display: grid | inline-grid

grid - block-level grid
inline-grid - inline-level grid

columns and rows

Define columns and rows via space-separated track sizes

.container {
  grid-template-columns: 40px 50px auto 50px 40px;
  grid-template-rows: 25% 100px auto;
}

Code above generates this. Note that line numbers are assigned automatically.

Can use line numbers to change order, or preferably, use shorthand syntax, or even shorter with grid-area

Can optionally name lines:

.container {
  grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
  grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
}

Can even give a line multiple names:

.container {
  grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}

Can repeat to save typing:

.container {
  grid-template-columns: repeat(3, 20px [col-start]);
}

Above is equivalent to:

.container {
  grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
}

If multiple lines have the same name, you can slap a count on the end. This references the 2nd col-start line

.item {
  grid-column-start: col-start 2;
}

Use fr to set size as a fraction of the grid container's free space:

.container {
  grid-template-columns: 1fr 1fr 1fr;
}

This is calculated after any non-flexible items. For example, the free space here is the total space minus 50px:

.container {
  grid-template-columns: 1fr 50px 1fr 1fr;
}

grid-template-areas
Defines a grid template. How? It references grid-area's by name. 3 potential values:

  1. <grid-area-name> - The targeted grid-area
  2. A period - signifies an empty cell.
  3. none - no grid areas defined.

Note grid-template-areas below: The syntax visualizes the grid's structure! 👍

.item-a {
  grid-area: header;
}
.item-b {
  grid-area: main;
}
.item-c {
  grid-area: sidebar;
}
.item-d {
  grid-area: footer;
}

.container {
  display: grid;
  grid-template-columns: 50px 50px 50px 50px;
  grid-template-rows: auto;
  grid-template-areas: 
    "header header header header"
    "main main . sidebar"
    "footer footer footer footer";
}

Above produces this.

Each row in the declaration needs to have the same number of cells. This syntax names areas. The associated lines are automatically named. So if your grid area is called header, the area's starting row line will be header-start, and the last row line will be called header-end. So some lines might have multiple names such as main-start, header-start, etc.

grid-template
Shorthand for grid-template-rows, grid-template-columns, and grid-template-areas in one declaration.

Values:

  • none - sets all 3 to their initial values
  • <grid-template-rows/grid-template-columns> - sets grid-template-columns and grid-template-rows to the specified values, respectively. Sets grid-template-areas to none.

So this:

.container {
  grid-template:
    [row1-start] "header header header" 25px [row1-end]
    [row2-start] "footer footer footer" 25px [row2-end]
    / auto 50px auto;
}

is equivalent to:

.container {
  grid-template-rows: [row1-start] 25px [row1-end row2-start] 25px [row2-end];
  grid-template-columns: auto 50px auto;
  grid-template-areas: 
    "header header header" 
    "footer footer footer";
}

Note: You typically want to use grid instead. Why? Because grid-template doesn't reset the implicit grid properties (grid-auto-columns, grid-auto-rows, and grid-auto-flow`), which you probably want to do.

grid-column-gap
grid-row-gap
Set gap between cells (okay, technically sets the grid line size).

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px; 
  grid-column-gap: 10px;
  grid-row-gap: 15px;
}

Result

Note: Gutters aren't added on the outer edges. Only between columns/rows. Also, the grid- prefix will be removed and grid-column-gap and grid-row-gap renamed to column-gap and row-gap. The unprefixed properties are already supported in Chrome 68+, Safari 11.2 Release 50+ and Opera 54+.

grid-gap
Shorthand for grid-row-gap and grid-column-gap

.container {
  grid-template-columns: 100px 50px 100px;
  grid-template-rows: 80px auto 80px; 
  grid-gap: 15px 10px;
}

If no grid-row-gap is specified, it's set to the same value as grid-column-gap

Note: The grid- prefix will be removed and grid-gap renamed to gap. The unprefixed property is already supported in Chrome 68+, Safari 11.2 Release 50+ and Opera 54+.

justify-items
Aligns grid items horizontally. (align-items does the opposite, it aligns vertically)

Values:

  • start
  • end
  • center
  • stretch

Can be set on individual grid items via justify-self.

align-items
Aligns grid items vertically. See justify-items above for horiz. Same values as justify-items.

Can be set on individual items via align-self.

place items
Shorthand. Sets align-items and justify-items. First val is align, second is justify. Not supported in Edge yet.

justify-content
Aligns entire grid horizontally inside container. So, only applicable when grid doesn't fill entire container).

Values:

  • start
  • end
  • center
  • stretch
  • space-around
  • space-between
  • space-evenly

align-content
Same as justify-content above, but vertically aligns.

place-content
Sets both align-content and justify-content, align listed first, justify 2nd. Not in Edge yet.

grid-auto-rows
grid-auto-columns
Sets the size of any auto-generated grid tracks (aka implicit grid tracks). These are created when there are more grid items than cells in the grid.

Example:

You create a container with a 2x2 grid:

.container {
  grid-template-columns: 60px 60px;
  grid-template-rows: 90px 90px;
}

But then you position items like this:

.item-a {
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}
.item-b {
  grid-column: 5 / 6;
  grid-row: 2 / 3;
}

This tells item-b to start on column line 5 and end on 6. But we never defined that column, so it results in this! So implicit tracks are created. This setting specifies the width of those auto-generated columns:

.container {
  grid-auto-columns: 60px;
}

New result

grid-auto-flow
If you have grid items that you don't explicitly place on the grid, this controls how they're automatically placed.

Values:
row - fill each row in turn, add new rows as needed
column - fill each column in turn, add new columns as needed
dense - fill in holes earlier in the grid if smaller items come up later

.container {
  grid-auto-flow: row | column | row dense | column dense;
}

Note: Dense changes the visual order, which might cause them to display out of order. Consider the a11y risks of this.

Example:

Step 1: Declare some html for 5 columns

<section class="container">
  <div class="item-a">item-a</div>
  <div class="item-b">item-b</div>
  <div class="item-c">item-c</div>
  <div class="item-d">item-d</div>
  <div class="item-e">item-e</div>
</section>

Then, declare a grid with 5 columns, 2 rows:

.container {
  display: grid;
  grid-template-columns: 60px 60px 60px 60px 60px;
  grid-template-rows: 30px 30px;
  grid-auto-flow: row;
}

Then, when placing them on the grid, only specify spots for 2:

.item-a {
  grid-column: 1;
  grid-row: 1 / 3;
}
.item-e {
  grid-column: 5;
  grid-row: 1 / 3;
}

Because grid-auto-flow is set to row above, the grid looks like this.

If we switch grid-auto-flow to column, then item-b, c, and d will flow down columns instead.

grid
Shorthand for grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, grid-auto-flow.

These 2 are equivalent:

.container {
    grid-template-rows: 100px 300px;
    grid-template-columns: 3fr 1fr;
  }
.container {
    grid: 100px 300px / 3fr 1fr;
  }

These 2 are equivalent:

.container {
    grid-auto-flow: row;
    grid-template-columns: 200px 1fr;
  }
.container {
    grid: auto-flow / 200px 1fr;
  }

These 2 are equivalent:

.container {
    grid-template-rows: 100px 300px;
    grid-auto-flow: column;
    grid-auto-columns: 200px;
  }
.container {
    grid: 100px 300px / auto-flow 200px;
  }

Finally, a more complex example that sets grid-template-areas, grid-template-rows, and grid-template columns - all other properties are set to their initial values. So this specifies line names and track sizes inline with their grid areas.

These are equivalent:

.container {
    grid-template-areas: 
      "header header header"
      "footer footer footer";
    grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
    grid-template-columns: auto 50px auto;    
  }
.container {
    grid: [row1-start] "header header header" 1fr [row1-end]
          [row2-start] "footer footer footer" 25px [row2-end]
          / auto 50px auto;
  }

Grid Item properties (the children)

Note: float, display: inline-block, display: table-cell, vertical-align and column-* properties have no effect on a grid item.

grid-column-start
grid-column-end
grid-row-start
grid-row-end
Determines the grid item's location in the grid. Refers to specific grid lines. *-start is where it begins. *-end is where the item ends.

Values:

  • <line> - Can be a number (to refer to a numbered grid line) or name (to refer to a named grid line)
  • span - number of grid tracks to span across, or name of line where it should stop
  • auto - auto-placement. Default span of one.
.item {
  grid-column-start: <number> | <name> | span <number> | span <name> | auto;
  grid-column-end: <number> | <name> | span <number> | span <name> | auto;
  grid-row-start: <number> | <name> | span <number> | span <name> | auto;
  grid-row-end: <number> | <name> | span <number> | span <name> | auto;
}
.item-a {
  grid-column-start: 2;
  grid-column-end: five;
  grid-row-start: row1-start;
  grid-row-end: 3;
}

Result

If no grid-column-end/grid-row-end is declared, the item will span 1 track by default.

Items can overlap each other. You can use z-index to control their stacking order.

grid-column
grid-row
Shorthand for grid-column-start + grid-column-end and grid-row-start + grid-row-end respectively.

This sets row to start at line 3, and ends at line 4. And sets the column to start at line 3 and end 2 lines later (line 5). Result.

.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}

Note: If no end value is declared, the item will span one item by default.

grid-area
Gives item a name so it can be referenced by grid-template-areas.

This assigns the name:

.item-d {
  grid-area: header;
}

Can also be used as shorthand for grid-row-start + grid-column-start + grid-row-end + grid-column-end:

.item-d {
  grid-area: 1 / col4-start / last-line / 6;
}

Result

justify-self
Horiz align (along row) a single item inside a cell

Values:
start
end
center
stretch

align-self
Like justify-self, but for vert align (column).

place-self
Shorthand for setting both align-self and justify-self, in that order. So vert, then horiz.

.item-a {
  place-self: center stretch;
}

Special funcs and keywords

When sizing rows/columns, you can use all the usual lengths like px, %. But also have keywords like min-content, max-content and fractional units.

  • minmax can set boundaries for otherwise flexible units. For example to set a column to be 1fr, but shrink no further than 200px: grid-template-columns: 1fr minmax(200px, 1fr);
  • repeat() - saves typing. Example: Make 10 columns: grid-template-columns: repeat(10, 1fr);

Combining all of these things can be extremely powerful, like grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

Codepen of above

Examples

Simple example
Named grid areas
[Excellent simple responsive grid with media query example]
(https://gridbyexample.com/examples/example13/)
Source order doesn't effect grid - can weave ads from bottom into content
Repeat example
Layering
Auto placement
Auto flow columns instead of rows
Mix auto placement with placed item
Full site example - Compare to Flexbox version.
Complex grid layout example

Grid resources

Josh Comeau's interactive guide
CSS Grid Generator
Box alignment cheatsheet - Compares Flexbox and Grid alignment
Grid by example
Grid Critters learning game

Demo App Checklist

Initial Order

  • Hello world
  • Display hard coded data
  • Display list from an API call
  • Delete item from list
  • Add item to list
  • Refactor to separate manage page
  • Add React Router
  • Edit item in list

Core features

  • Display tabular list
  • Add item
  • Edit item
  • Delete item
  • Treat state as immutable
  • Validate before save
  • Handle numeric form value (default to empty string, use parseInt when resetting)
  • Declare defaultProps for TextInput (Default disable to false)
  • Implement footer
  • Hide list when no records exist (conditional rendering)
  • Disable save button until form is populated when adding (Use derived state)
  • Show number of items in header link
  • Publish list as a reusable component on npm
  • Set focus on first form field via ref (yes, doable native via autofocus too)
  • Handle async calls
  • Use immer to handle a state transition
  • Filter list
  • Sort list
  • Use Barrel pattern to shorten imports for components in dedicated folders
  • Avoid calling setState on unmounted components by cancelling any async work
  • Implement login
  • Display "Hello username" in header
  • Use username when saving records

React fundamentals

  • Utilize centralized propTypes with exact shapes
  • Wrap peer elements in Fragment
  • Add ErrorBoundary
  • Use lifecycle / hook to request data on mount
  • Handle data via context
  • Use class and function components with Hooks
  • Use functional setState
  • Use destructuring to shorten calls in render
  • Use destructuring in functional component argument lists
  • Use standardized event handler names (onX when passed, handleX when handled)
  • Utilize all hooks

State

Performance

  • Load large dataset and add filters. Note that rendering gets slow as filters change
  • Lazy load routes and display spinner via Suspense
  • Implement shouldComponentUpdate / PureComponent / useMemo on long list of records to avoid needless re-renders
  • Timeout calls using promise.race and display an error page after x seconds.
  • More in #77

Reusable components

  • Consume a reusable component: Use react-toastr for notifications, React bootstrap table
  • Implement reusable TextInput and document it
  • Create reusable component build

Routing

  • Handle 404s
  • Route between pages
  • Style active link
  • Set page titles
  • Redirect

Styling

  • Apply at least one inline style
  • Reference a dedicated CSS file for each component

Redux

  • Implement action creator, action constants, store, reducers, and connected components
  • Utilize Redux thunk for async calls
  • Configure Redux dev tools

React Frameworks

My Tweet thread on create-react-app alternatives

Related: My take on how to choose between SPA and SSR

Client-rendered

Content-focused / Static site

  • Gatsby - Deferred Static Generation, integrated GraphQL
  • Astrobuild - Can mix with Vue, Angular, Svelte, etc too. Can add dynamism via API calls during build.
  • Docusaurus

Server-rendered, no DB included - comparo vid

  • #78 - Built-in routing, image optimization, easy deploy. More
  • #79 - Built-in file based routing, Embraces web standards to streamline forms, co-locates server code inside components via loaders. Put links in head by exporting links function. CSS is automatically tied to the page. Fast build built in Go. More #79. Next vs Remix by Ryan Florence and here's another Next vs Remix blog post
  • Gatsby (added SSR in V4)
  • After.js (Like Next, but with React Router routing)
  • t3app - Next, but with extra opinions like Prisma, Tailwind, trpc with Zod

Server-rendered, DB included

  • Redwood - Unlike Blitz, built from the ground up. But much like Blitz, but uses GraphQL instead of REST with Prisma. end-to-end test suite, Storybook, logging, Auth, MSW, Router, Prerendering, Webhook security and testing. The underlying architectures of Next and Redwood are fundamentally different. Redwood's client is an SPA with prerender-by-route config. Cell components are a unique innovation for data fetching + state, resembling "islands of interactivity" design. Redwood's multi-client, GraphQL API is secure-by-default using pre-configure defaults and Auth directives (which can also transform data). The API Services are another innovation and include data validators. And it's cache-ready, meaning it just requires infra setup to enable.
  • Blitz - Next.js extensions for API, Jest, ESLint, Prettier, Auth, command line based file generators, and Prisma DB built in. Abstracts the API into a compile step and generates plain functions that can be called on the client. Funded via Y-Combinator because of their cloud offering.

Nearly 200 more options

Not React, but similar

Preact
SolidJS
Marko - Also Marko vs React
Qwik

React Quiz

  1. What is react?
  2. What is the benefit of doing client-side Development?
  3. Why use react router?
  4. How did we declare routes? Where? Using what component? How did we avoid / matching all routes?
  5. What is JSX?
  6. What are props?
  7. What does JSX compile down to?
  8. What is create react app?
  9. What tools does create react app use behind the scenes and why?
  10. What command do you use to start the application?
  11. Where is the script you’re running?
  12. Tell me about the history of JavaScript and how new features get added.
  13. Are there alternatives to create react out? If so how would you find them and why would you consider them?
  14. What does the curly brace mean in JSX?
  15. How do you handle public vs private?
  16. What folder does node install dependencies into?
  17. What language are those files written then? Can you view them?
  18. Where are our apps dependencies declared?
  19. What is the syntax for importing react?
  20. What is the name for that syntax?
  21. What if I want to import a specific portion of a file?
  22. When do we use a relative path in import?
  23. What if we omit the path in an import?
  24. What does that syntax look like?
  25. What is that style of import called?
  26. What JavaScript array method do we use to return a new array?
  27. What are two ways to create an object in JavaScript?
  28. JavaScript is a prototypal language. What does that mean?
  29. What tool are we using to format our code?
  30. What is a key? When an why is it useful? What value should we set it to?
  31. What is a pure function? Why is it useful?
  32. What is the computed property syntax? When is it useful?

Media Queries

Why Media queries? Include some CSS when some condition is true.

Example:

@media only screen and (max-width: 600px) {
  body {
    background-color: lightblue;
  }
}

Make background blue when in landscape mode (width > height)

@media only screen and (orientation: landscape) {
  body {
    background-color: lightblue;
  }
}

Show content on > 600px screen (this assumes hidden by default in separate CSS):

@media only screen and (min-width: 600px) {
  div.example {
    display: block;
  }
}

Media Types

  • all - default
  • screen - Computer screens, tablets, smart-phones
  • print - applies when printing hit print here for Example.
  • speech - For screen readers
<link rel="stylesheet" media="screen" href="styles.css"/>
<link rel="stylesheet" media="print" href="print-styles.css"/>
@media screen {
  body {
    color: white;
    background-color: black;
  }
}

@media print {
  body {
    color: white;
    background-color: black;
  }
}

Can even apply a stylesheet for specific screens:

<link rel="stylesheet" media="screen and (max-width: 600px)" href="smallscreen.css">

For multiple options, a comma operates as an OR.

Example: When the width is between 600px and 900px OR above 1100px - change the appearance of

@media screen and (max-width: 900px) and (min-width: 600px), (min-width: 1100px) {
  div.example {
    font-size: 50px;
    padding: 50px;
    border: 8px solid black;
    background: yellow;
  }
}

Media Features

Useful for applying media query in specific circumstances such as viewport width/height, orientation, and prefers-* rules that convey the user's preferences. Full list on MDN.

The prefers-* settings use OS level settings. Examples: color-scheme and reduced-motion.

@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}

Run JS based on media queries

Can use window.matchMedia() to run JS that matches a media query. Also consider MediaQueryList, though not as broadly supported.

  • Normalizing cutoff points
    • Built into Bootstrap
  • Setting meta tags for viewports 

React

react-responsive - Hook for declarative breakpoints.

React State

Overview

Here is a superb post that comprehensively reviews where we've been, where we are, and why. And it clearly outlines the tradeoffs inherent in different libraries and approaches.

The new wave of state management tools is mostly about reducing paradigms. Take a principle (flux, proxies, atoms, ...) and reduce it to the smallest possible outcome based on modern JS and React semantics without losing functionality or performance. That's these new state managers:

  • Zustand is Redux w/o clutter (Like Redux, abstracts access to state via actions, events, etc)
  • Jotai is Recoil simplified to 2 apis (Like context, provides a global, but better perf, and accessible outside of React)
  • Valtio is Mobx simplified to 2 apis - Unlike Jotai, supports deep subs
  • Legend offers simple observables, that support mutation, and can be easily persisted to localStorage or other spots. A modern version of MobX with enough features to replicate MobX-State-Tree but with a lot less overhead.
  • Signal - Uses immutable objects with stable identity (like refs) which avoids re-renders. Provides a value property for accessing the current value. Surgically updates the DOM in Preact. It was created for Preact, but works with React too. Unlike hooks, can declare the state outside of components! So a great alternative to Context. If a signal’s value hasn’t changed, components and effects that use that signal’s value won’t be updated, even if the signal’s dependencies have changed. Dependencies across signals are automatically tracked (no dependency arrays).

8 Ways to Handle State

image

Built into React

Class state
useState
useReducer
context/useContext
refs/useRef

Remote state

swr
react-query
Apollo
Relay

Form state

formik
react-hook-form - my demo using Zod for validation
react-form
react-final-form

URL / location state

React Router
useSearchParamsState - A convenient wrapper over React Router's anemic useSearchParams hook.

General state

Redux
Flux
Mobx
Recoil
XState
Valtio
Unstated
mobx-react-lite
easy-peasy
overmindjs
react-easy-state
Effector
freezer
Undux
Zustand
react-sweet-state
Statux

https://twitter.com/DavidKPiano/status/1353712136372039682
image

Image below from https://rockiger.com/en/react-state-management/
image

Modern JavaScript

Modern JavaScript

ES Modules

  • ES modules vs CommonJS Simple example - Video
  • Imports
    • Named imports
    • Wildcard imports
    • Aliasing imports via as
    • Dynamic import
  • Exports
    • Default exports
    • Export * from a module
    • Exporting multiple functions at the bottom of the file (looks like an object, but technically isn't).
  • Barrel pattern
  • Show what these look like in Babel
  • ES modules must be statically analyzable (for tree shaking, autocomplete, and compile-time checks like eslint-plugin-import 👍)

Debugging

  • Use debugger to pause
  • console.table to display object in table
  • console.timer/console.timerEnd to check perf
  • console.assert to log a specific message to the console if an expected value isn't true
  • console.count/console.countReset to count the number of times a certain string has been logged.
  • Visual examples of the console features above

Native iterators

Don't confuse these!

  • for...of - Loop over iterables (arrays, strings, and array-like arguments.
  • for...in - Iterate over object properties

Functional Approaches

Copying Objects and Immutable data Structures

Async Patterns

  • Async patterns
    • Callbacks
    • Promises - A promise is a container that you get immediately for a value that you get eventually. Objects that represent the outcome of an event that may not yet have occurred.
      • Promise.all
      • Promise.race - Useful for timing out requests after x seconds.
      • Declare catch or it may swallow exceptions!
      • finally was added in ES2018 - always runs, regardless of resolve or rejection.
    • allSettled - Like promises.all, but the .then runs after all promises are settled, regardless of resolved or rejected.
    • Async/Await
  • Async cheatsheet

Regex

Other Patterns

Summary

Performance Checklist

42+ ways to make your React app faster ⚛️:

Performance Testing

Generate a simple fake dataset in a loop.

export function generateProducts() {
  const products = [];
  for (let i = 0; i < 10000; i++) {
    products.push(`Product ${i+1}`);
  }
  return products;
}

Generate a large fake dataset using tools like Faker, Chance, etc.

import faker from "faker";

export const fakeNames = Array.from(Array(10000), () => {
  return faker.name.findName();
});

Simulate a slow component via a loop:

function ExpensiveTree() {
  let now = performance.now();
  while (performance.now() - now < 100) {
    // Artificial delay -- do nothing for 100ms
  }
  return <p>I am a very slow component tree.</p>;
}

Forms

HTTP

Rendering

  • Statically render if possible (Easy via Next.js, Gatsby)
  • Lift fetches to common parent or fetch in parallel via tools consider server rendering to avoid slow network waterfalls (easy via Remix / Next.js)
  • Prefetch / render-as-you-fetch (React's "default" is fetch as you render since the render triggers a fetch via useEffect). React-query's prefetching is a simple way to render as you fetch. Remix also does this by default since nested routes declare data dependencies and run in parallel on the server. My tweet on this
  • If server rendering with Remix, Next, Docusaurus, etc, Enable time-slicing with React.startTransition at the root. This avoids jank if the user scrolls before hydration completes.
  • Consider using million's block virtual DOM instead if there is a lot of static content with little dynamic content. Million diffs state instead of DOM, which is fast if there's a little state, but a LOT of DOM.

Context

Routing

  • Implement client-side routing via React Router (or you frameworks built-in alternative, such as Next.js)

Keys

  • Assure keys are assigned, and stable over time. Their values should not change based on array order or edits to the data.
  • Reuse keys to avoid needless renders for items that frequently appear/disappear in the viewport.
  • Consider using the array’s index as key for dynamic lists with stateless items, where items are replaced with the new ones - paginated lists, search and autocomplete results and the like. This will improve the list’s performance because the entire thing doesn't have to re-render. The component instances are reused. Demo and blog post

State

  • Keep state as local as possible. Start by declaring state in the component that uses it. Lift as needed.
  • Store data that doesn't need to render in refs
  • Consider useReducer over useState so you can pass dispatch down instead of callbacks (avoids needless renders)
  • Avoid deep cloning. To avoid, only clone the subobjects that have changed. Or perhaps better yet, avoid nesting objects in state since doing so can lead to needless renders. Instead, "flatten" state by creating separate pieces of state.
  • Use memo, ref, or pass a func to useState if the initial value calls an expensive func, otherwise, it will be calculated on each render.
  • Use useTransition for low priority updates (reduces jank) - Demo
  • Use useLayoutEffect to avoid a Flash of unstyled content when you need to read and manipulate the DOM before the user sees it - Demo

Memoization / Identity

  • Memoize expensive operations via useMemo
  • Avoid needless renders via React.memo
  • Consider wrapping functions passed to children in useCallback to avoid needless renders in children
  • Prefer pure functions (which can be extracted from the component) over useCallback when possible

Props

  • Pass the minimal amount of data to each component (remember, components re-render when props change)
  • Pass primitives (strings, numbers...) to child components to assist with diffing. Avoid passing arrow funcs and objects on props when performance is a concern since it leads to needless re-renders of child components.
  • useDeferredValue if it's a low priority update and you can't use useTransition because you don't control the value coming in (coming from third party or via a prop you can't control). Another demo

Component composition / Children

  • Put content that renders frequently in a separate component to minimize the amount that's rendered
  • Embrace reusable components. Each reuse of a reusable component is nearly free.
  • Compose higher level components out of lower level components.
  • Create layout components to centralize reusable layout
  • Lift content up - Pass children down (do this before you memo). Why does this work? Because components passed as children don’t re-render since they are just props. Note: don't pass a function as a child, since it'll still re-render because the func will be recreated on each render
  • Declare functions that need not be in the React component outside the component. This way they're not reallocated on every render.
  • Declare static values outside the component so they're not reallocated on every render.

Design

  • Use pagination, sorting, filtering, pages, tabs, accordions, modals, etc to avoid displaying too much data at the same time.
  • Use tools like react-window to handle large lists by only rendering what's currently visible.
  • Consider implementing optimistic updates when the API is slow (immediately update the UI even though the API call is still in progress behind the scenes)

Bundle optimization

Third party libraries

  • Avoid named imports when importing third party libraries / components (doing so can bloat the bundle by importing the entire lib) For example, avoid import { Tab } from "x". Prefer import Tab from "x/Tab" when possible.
  • Prefer native HTML inputs over fancy components that simulate native behaviors
  • Use Partytown to load heavy third party libraries via a separate web worker thread

Styling

  • Consider Tailwind to minimize style bundle size
  • Consider CSS modules over CSS-in-JS to avoid a runtime

Framework

  • Consider Gatsby or Astrobuild to compile components into static HTML
  • Consider Next.js, Remix, Redwood to server render

More examples

https://piyushsinha.tech/optimizing-performance-in-react-apps-i
https://piyushsinha.tech/optimizing-performance-in-react-apps-ii

Recommended Resources / Next steps

Here's some recommended next steps.

First: Remember the learning principles from day one.

  • Start with why. I'm going to ask the group why first.
  • Feynman technique: "If you can’t explain something in simple terms, you don’t understand it" Richard Feynman. The act of thinking is helpful. The act of explanation clarifies your understanding and exposes holes. Teaching exposes sloppy understanding.
  • Perform challenges. "What I cannot create, I do not understand." Richard Feynman "To learn and not to do is really not to learn. To know and not to do is really not to know." Stephen Covey
  • Repeat: Repetition helps us remember. Our brains assign greater importance to repeated information.
  • Practice retrieval: Create flash cards to quiz yourself on key concepts like Lift state, JSX vs html, State, Cloning objects, Props, PropTypes.
  • Spacing effect: We are better able to recall information and concepts if we learn them in multiple, spread-out sessions. So we'll review regularly. Retrieving memories changes the way they are later encoded. The harder something is to remember now, the better we will recall it in the future. The more we strain, the easier it will be in the future.

React Docs

Read the docs. Beginning to end. Set a calendar invite for 30 minutes a day until you're done. They're superb.

Blogs

Overreacted.io - Written by Dan Abramov (on the React team)

A few favorites:

Videos

Code Worth Reading

More Resources

Agenda: athenahealth Watertown

Details
Wednesday, Nov 6, 2019
8:30 AM - 4 PM - Group sessions

Thursday, Nov 7 , 2019
8:30 AM - 9:30 AM – Consult session with Cory House
Room: Building 313, Room 222
8:30 AM to 8:50 AM – COLCR - @hannah Thomas@Harris Gilliam@Aaron Moronez@Nolan Martin
9:00 AM to 9:20 AM - Content Team – @faraz Ali @ben Oehlkers @ahmer Khan
9:30 AM - 4 PM - Group sessions. Break for lunch at noon.

12 PM - 1 PM - Consult session with Cory House
Room: Building 313, Room 222
12:00 PM to 12:20 PM – COLCC – @Megan Donnelly
12:30 PM to 12:50 PM – COLCP - @olivia Adams

Friday, Nov 8 , 2019
8:30 AM - 9:30 AM Consult session with Cory House
Room: Building 313, Room 222
9:30 AM - 4 PM - Group sessions

Storybook

  • Use to document all app's reusable components
  • Can create a single storybook for a monorepo, grouped by application. This helps expose potential reusable components.
  • Consider knobs
    • Can put full app in Storybook and make actual calls to APIs - allow selecting environment via Knobs
    • Can use Storybook knobs to hit different environments on "smart" components or app portions

Kiewit Agenda

Topics

Modern JavaScript
React Fundamentals
Advanced React

Lunch 11:30

9 - 4 Daily

  • Forms and state
  • Reusable components
  • Storybook
  • useState, useReducer, useEffect
  • Context, vs Redux
  • advanced Hooks
  • Custom hooks
  • Automated testing Jest, Enzyme, RTL, Cypress
  • Security
  • Styling (tech and patterns, convo about standards)
  • Code review (standards, opportunities, tech choices, patterns, practices, programmatic enforcement)
    • Reusable components via npm

Advanced React Agenda - Paycor

Overview

9 - 4ish EST Daily
Breaks once/hour - get away from the machine! 🏃‍♂️💨
Please mute when not speaking
Post "done" in chat when done with an exercise
Let's dialogue like we did in person
Lunch at 12:30 EST?

Agenda

Tweak existing app

  • Change hair color to role with a dropdown.
  • Convert user class to func
  • Add Nodemon to hot reload apiServer changes

Reusable components

  • Signs it's time to consider extracting a component
  • Install Storybook
    • Configure to look in /src
    • Explain CSF vs storyOf
    • Add Input component story
    • Add knobs
  • Create reusable Select based on Input
  • Slides for fundamentals
  • Add propType comments
  • Place Input in folder, then barrel
  • Wrap an existing component - Create Accordion via react-animate-height
  • Create H1 as example of styling only component
  • Create SubmitButton with optional cancel included
  • Compound components
    • Exercise - Tab control approaches - See compound components here
  • Responsive mobile vs web - separate components lazy loaded - see Responsive tables here
    • Create reusable course card. Display data as a card when on mobile.

Barrel Pattern

Children

  • Create simple layout in App.js
  • Slot pattern: Create layout component with slots to support with header above nav
    • Accept heading as either a string or an element. use isValidElement to compose either.
    • Use React.cloneElement to add React Router props to child element passed in
    • Exercise: Use slot pattern to create card component with Heading, body, and footer with gray background.

Cypress Driven Dev

  • Add @testing-library/cypress 
  • Add https://github.com/cypress-io/eslint-plugin-cypress
  • Update User.spec.js to use Cy testing lib queries
  • Setup scenario selector
    • Create ScenarioSelector component and style it
    • Fork api proxies for prod and mock
    • Pass scenarios on header via API proxy
    • Enhance apiServer.js to read different scenarios

Error Handling

  • Create 404 Page
  • Redirect unmatched routes
  • Create ErrorPage
  • Add API call error handling
    • console.error in api proxy
    • redirect to ErrorPage in app
  • ErrorBoundary
    • Create App ErrorBoundary that embeds ErrorsPage
    • Create nested ErrorBoundary for portion of app
  • Discuss error logging services

Advanced State

  • Challenge: Show number of courses next to the header link. How?
  • Lift course state to avoid reloads
    • Use functional setState to add course to existing state
    • Declare propTypes for Users and ManageUser. Declare exact shape
    • Centralize user propType
  • Use Immer for handling state changes
  • UseReducer for course page state
    • Automated test reducer
  • Avoid calling setState on unmounted components
  • Use context for login
    • See context here for details
    • Display hello username in the header
    • Add updatedBy when saving
    • Exercise: Context for course state
    • Exercise: use context to create our own Toast system with a fixed location just below the nav.
    • Exercise: Add i18n on navigation or greeting with a toggle button for English/Español.

Props

  • Spread props on Input to show how some props can be destructured, others not.

API

  • Convert to async/await
  • Centralize apiUtils to streamline

Other Advanced Hooks

  • useRef to focus first input on manageCourse
    • Use forwardRef to support forwarding ref to the input
  • create custom hook for handling async (or for displaying mouse coords)
  • Create useLocalStorage custom hook and use on scenario selector.
  • useLayoutEffect

Routing

  • Lazy load pages with React.lazy and Suspense
  • Add auto scroll on route change

Performance

  • Switch to large user dataset
    • Add filter and sort fields with a submit. Note that as you enter keystrokes, the table redraws slowly.
    • Wrap component in React.memo so it only re-renders when form is resubmitted (check submit counter)

Redux

  • Slide intro
  • Convert app to use Redux for courses in a branch
    • Exercise: handle another part of CRUD on your own.
    • Exercise: handle user info via Redux

To do

Pick advanced hook demos
Create large dataset for perf testing
Find a useCallback and useLayoutEffect examples

Company Framework

Company Framework

Goal: A standardized React development approach for your company.

Current Status

  • How many React projects exist?
  • How do you start new projects today?
  • What are your pain points?
  • What comes up often in code reviews?
  • What fragmentation exists currently?

Why?

  • Programmatically enforce consistency
  • Speed code reviews
  • Foster cross-team collaboration
  • Ease ongoing maintenance
  • Centralizes bug fixes
  • Centralize updates and coordination among versions of dozens of packages
  • Avoid ongoing decision fatigue
  • Avoid reimplementation overhead
  • Systematize corporate knowledge
  • Automate best practices - make doing the right thing the easy thing
  • Create a common foundation upon which to run reusable components
  • More here.

Decisions

Transpiling

Bundler

  • Webpack, Browserify, Parcel, Rollup…

Linting

  • Which linter?
  • Warnings, errors, or both?
  • Publish your own linting plugin
  • Select plugins
    • eslint-plugin-import
    • eslint-plugin-jsx-a11y
    • eslint-plugin-lean-imports
    • Lint testing files too via eslint-plugin-jest?
  • Select settings
    • Start from recommended, existing plugin, or from scratch?
    • Forbid some imports?
    • Enforce style, or use Prettier or editorconfig?
  • Run lint and prettier on commit via husky?
  • Enable which rules?
  • Use a preset?

Testing

  • Framework?
  • Assertion Library?
  • Helpers?
  • Test file location? Alongside or under /test?
  • File naming?
  • What environment?
  • Mocking?
  • Code Coverage
  • Continuous Integration
  • When to run tests
  • Test for forbidden dependencies. Here is an example. Your base bundle needs to depend on the routes, because when you go from A to B, you need to already know the route for B, so it has to always be around. But what you really don’t want in the base bundle is any form of UI code, because depending on how a user enters your app, there might be different UI. So, for example the date picker should absolutely not be in your base bundle, and neither should the checkout flow. Assert that the base bundle doesn't contain any libraries that can be lazy loaded. Avoid centralized dependencies. Instead, use the enhance pattern and generate code. Here's how: files can declare what they want to enhance and a code generator can find these files and generate the centralized file. Example: Put a "decorator" (e.g. ##ROUTEME##) in a file to mark it as relevant to the router. This avoids a centralized dependency, and when you want to delete the file, you can do so without touching some huge centralized file. This also makes it easy to delete code, which is what we should optimize for.

Project structure

  • Organize files by file type or feature?
  • Centralize API?
  • Allow Inline JS?
  • Extract to utils (POJOs)?

HTTP

  • Library
  • Mock schema format
  • Mock data generation
  • Mock server

Production build

  • Minification
  • Sourcemaps
  • Bundle splitting
  • Cache busting
  • Error logging
  • Automated Deployment to your preferred host
  • Error logging

Styling

  • Styling tech
  • Stylelint
  • Host styles on CDN

API Calls

  • REST vs GraphQL
  • Library
  • Centralized file location
  • Publish and bundle proxies?
  • Mock API
  • Suggest editor plugins via VSCode
  • Bundler
  • Automated File Generation via templates plop, Hygen
  • CLI vs Git clone

Monorepo

  • Convince a few consumers to place their project within your monorepo. Why?
    • Truly continuous integration = instant feedback on breaking changes
    • White glove handling of breaking changes
    • Easily test new ideas in a real world environment
    • Consider setting up CI to run for consuming projects when you publish betas. Walmart does this. This way you know when you've broken other projects.
  • Unified versioning?
  • Lerna
  • Yarn workspaces
    • Related projects to consider bundling in monorepo
      • Reusable components
      • App Starter
      • Component Starter
      • API Wrapper
  • Demo app
    • Show examples of file naming, locations, validation, folder structure, Redux configuration, performance approaches.
    • Highlight key features
    • Make it easy to remove

Documentation

  • Branding
  • Compose with style guide?
  • README.md
    • Why does this exist?
    • How do I report issues?
    • Who is using this?
    • How do I get started?
  • CONTRIBUTION.md

Release process

  • Semantic versioning
  • Release notes
  • Publicize via Slack, email. Collect emails of users.

Flexbox

Flexbox

Josh's wonderful interactive Flexbox guide

image

Old school: Split up page into 12 columns.

.col-1 {width: 8.33%;}
.col-2 {width: 16.66%;}
.col-3 {width: 25%;}
.col-4 {width: 33.33%;}
.col-5 {width: 41.66%;}
.col-6 {width: 50%;}
.col-7 {width: 58.33%;}
.col-8 {width: 66.66%;}
.col-9 {width: 75%;}
.col-10 {width: 83.33%;}
.col-11 {width: 91.66%;}
.col-12 {width: 100%;}
  • Efficiently layout items in a container (use Grid for large scale layout), even when their size isn't known (hence, flex box).
  • Big idea: Flex width/height to best fit the space. Expands to fill space or shrinks to prevent overflow.
  • Benefits: Simpler markup (no more wrappers, floats, etc), and reduced JS needs
  • Direction agnostic (unlike block which is vertical, and inline which is horizontal)
  • Browser support
  • Bootstrap uses Flexbox behind the scenes
  • container with items - img
  • Items are laid out following either the main axis from main-start to main-end or via the cross axis from cross-start to cross end. Main is not necessarily horizontal. The direction of each is impacted by flex-direction.

Key Terms

  • main size - A flex item's width/height (whichever is the main dimension).
  • cross axis - Perpendicular to main axis
  • cross-start | cross-end - Flex lines start at cross-start
  • cross-size - Width or height of flex item (whichever is in the cross dimension)

Properties

display

.container {
  display: flex; /* or inline-flex */
}

flex-direction
row is ltr, column is top to bottom.

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}

flex-wrap
By default, all items will try to fit on one line. So the default is nowrap. wrap will wrap top to bottom/left. wrap-reverse will reverse the align-items setting and the direction new lines are created. So it will wrap items to the top/right instead of the bottom/left (depending on the flex-direction). And note order: Flex wraps first, then shrinks/grows. if enabled. Regarding grow/shrink/ the item's current line is the only space that matters.

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}

flex-wrap demo

flex-flow (applies to parent flex container)
Shorthand for flex-direction and flex-wrap which together define the container's main and cross axes. Again, default is row nowrap

flex-flow: row wrap;

Above is same as:

flex-direction: row; flex-wrap: wrap;

justify-content
Defines alignment along the main axis. Distributes extra free space. Image

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}

align-items
Same as justify-content, but defines alignment on the cross axis. Image. Default: stretch.

.container {
  align-items: stretch | flex-start | flex-end | center | baseline;
}

align-content
This aligns the lines, so only applies when wrapping. Like justify-content, but for the cross-axis. Image

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

Properties for flex items

gap
gap allows us to create space in-between each Flex child, along the primary axis.

margin-left and margin-right
Set this to auto to add space around a specific element. It will gobble up the extra space, and apply it to the element's margin. It gives us precise control over where to distribute the extra space.

Screenshot 2022-12-03 at 7 58 08 AM

order
By default, flex items are laid out in source order. Can change using order:

.item {
  order: <integer>; /* default is 0 */
}

Any item with an order of 1 or higher gets sent to the back of the line. A negative order moves the item to the front of the line. Items with the same order setting will honor their source order.

flex-grow
Let item grow if necessary. Dictactes the amount of the available space in the container the item should take up. If all items have flex-grow set to the same value, the remaining space will be distributed equally. If one is set to 2, and others are set to one, it will take up twice as much space.

.item {
  flex-grow: <number>; /* default 0 */
}

flex-shrink
Opposite of flex-grow. Describes how the content should react when there's not enough space. Relative like flex-grow. Set to 0 to not allow an item to shrink.

.item {
  flex-shrink: <number>; /* default 1 */
}

flex-basis
The new and improved version of width and height, for flex, but only applies to the primary axis. Defines the element's default size before the remaining space is distributed. It's not a guarantee. It merely specifies an an "ideal" when there's enough space. So it's merely a starting point. This setting overrides width if set. min-width sets a lower limit. max-width sets an upper limit. Like width, can use % or px. This effects height instead when in column mode.

Also, when the total space available falls below the total of flex-basis for all elements, shrinking occurs. So flex-shrink effects the behavior at that point. And when extra space is available, their flex-grow setting effects if and how they grow.

Finally, if you set flex-basis lower than min-width, it becomes the min value. Same story with max-width.

  • auto: use items width or height property. The default.
  • content: size it based on item's content
.item {
  flex-basis: <length> | auto; /* default auto */
}

In general, we can use width and flex-basis interchangeably in a Flex row, but there are some exceptions. For example, the width property affects replaced elements like images differently than flex-basis. Also, width can reduce an item below its minimum size, while flex-basis can't.

flex
Shorthand for flex-grow, flex-shrink, and flex-basis combined, in that order. Only first param is required. Default is 0 1 0px. You can leave off the 2nd param too (since the last one is px or auto, it's not ambiguous. For example, this sets only grow and basis: flex: 0 300px;

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

Also, handy auto shortcut (grow, shrink, and use size as basis):

.item {
  flex: auto; /* sets flex-grow: 1; flex-shrink: 1; flex-basis: auto; */
}

And handy none shortcut (don't grow, don't shrink, and use your size as a basis):

.item {
  flex: none; /* flex-grow: 0; flex-shrink: 0; flex-basis: auto */
}

align-self
Override alignment for a single item. Works like align-items.

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

It's recommended to use this shorthand property. It sets the other values intelligently.

Cross-browser support

  • There are older versions of Flexbox (used by IE10/11.
  • Use autoprefixer

Useful tools / Resources

flexplorer
Box alignment cheatsheet - Compares Flexbox and Grid alignment
Solved by Flexbox - Examples of problems solved by Flexbox
Guide to Flexbox on CSS Tricks
List of bugs with current status

Examples

2 column responsive layout
Responsive table on Stackblitz (also in this repo)
Calendar Codepen
Full site layout - Compare to Grid version

Demo app ideas

  • User admin
  • Restaurant Menu CMS
  • Twitter clone
  • Workout tracker
  • Conference CMS
  • Shoe store
  • Auto dealership CMS
  • Chat app (fun to simulate via dev tools)

HTTP Calls and Mock APIs

Mock APIs

My Twitter thread

Tool API DB Data integrity Real HTTP Requests Setup
json-server Real (Express) lowDb Your job Yes Declare db.json, call mock base URL
Mirage Mock HTTP In memory w/ORM Yes No Declare routes, seed db in server object
msw Trap HTTP via SW No, see mswjs/data or save in-memory variables No Yes

Other mocking tools:
https://github.com/outbrain/Leonardo
https://mockoon.com/
https://www.smockin.com/

MSW tips:

Review plan

Honor the spacing effect.

“Repeated exposure to information in specifically timed intervals provides the most powerful way to fix memory into the brain. …Deliberately re-expose yourself to the information more elaborately, and in fixed, spaced intervals, if you want the retrieval to be the most vivid it can be. Learning occurs best when new information is incorporated gradually into the memory store.” - John Medina, Brain Rules

Open your calendar and schedule 15-30 minutes/day over the next 30 days.

Mailing Lists

Check out my JavaScript information stream

Challenges:

Build a new app that implement the same core features outlined in the demo checklist.
Create a class component
Create a functional component
Use a ref to set focus on an element
Build a TODO app
Enhance our existing app to review concepts daily

Development Environment

Development Environment

Discuss options and configure development environment for session

Monorepo tools

See #170

Debugging in VS Code

This adds integrated VSCode debugging support to our project.

To use:

  1. Install Debugger for Chrome
  2. Click the gutter to set a breakpoint (a red dot will appear)
  3. Click the bug to open the debug panel
  4. Click play to start debugging in Chrome (make sure Chrome is selected in the dropdown next to the play button). This will open a new browser window and pause on your breakpoint.
  5. You can hover over any variables to see their values. The variables window on the left is handy too.
  6. Click on Debug console to display a console where you can run code while debugged.

This is a handy way to debug because:

  1. You don't have to change the code (to add a debugger or console statement for instance) to debug.
  2. You can set conditional breakpoints and logpoints.

Recommended ESLint rules

Responsive Web Development with React

Agenda Overview

  • Responsive design intro
  • Core Tech (Media queries, Flexbox, CSS Grid) - Explore each. Code together.
  • React tools / libraries
  • Tables
  • Images
  • Tools

What is responsive design?

Core Tech

Old school

Modern Approaches

My CSS tech usage poll

Our Goal

  1. Know what's possible.
  2. Know what tools to reach for, and when.

Not our goal? Memorize dozens of key/value combos. That's what docs are for. Memorization comes naturally through use, over time.

Fundamentals

  1. Mobile first. Then widen, and add styles as needed (via media query). This leads to simpler CSS. Also loads faster on mobile (since desktop only CSS doesn't apply).
  2. Set viewport meta tag
  3. Prefer relative widths (like percents, fr in grid, grow/shrink in flexbox) to avoid horiz scroll (caused by large, fixed width elements or large absolute positioning values)
  4. Don't tie design to a particular screen width or device. There's a huge variety. Instead, use Media queries, Flexbox, and CSS Grid to assure the design looks great at all widths.
  5. Use box sizing, border-box to simplify styles. * { box-sizing: border-box; } This means padding and border are included in the element's total width and height.
  6. Infer scroll/swipeability - Use overflow shadows or hang content partially off-screen

Media queries

Flexbox

CSS Grid

Images

This will honor the image's aspect ratio, and scale down as needed. Example:

img {
  max-width: 100%;
  height: auto;
}

Can use media queries to serve different images for different screens

/* For devices smaller than 400px: */
body {
  background-image: url('img_smallflower.jpg');
}

/* For devices 400px and larger: */
@media only screen and (min-device-width: 400px) {
  body {
    background-image: url('img_flowers.jpg');
  }
}

Use <picture> to declare multiple sources. Demo. Note: Use <img srcset instead for high DPI.

<picture>
  <source srcset="mdn-logo-wide.png" media="(min-width: 600px)">
  <img src="mdn-logo-narrow.png" alt="MDN">
</picture>

Responsive Tables

Responsive Bootstrap table
Responsive tables on CSS tricks
Responsive table roundup on CSS tricks
Flipped axis
Hide columns, but optionally show again and display horiz scroll
Tablesaw - A library of options
React Super responsive table
Or, simply build two separate components and lazy load the relevant one (a vertically-oriented design for mobile and a traditional table for desktop). Consider, the desktop design may have sorting, filtering built into headers, while mobile design may use separate filter/sort UI above. Splitting allows for optimizing each experience. Can use react-responsive for clean, declarative media queries. Codesandbox - Demo on Netlify - Watch network tab.

React Techniques

Performance

  • Lazy load either web or mobile via React.lazy (see example above under tables)
  • Normalize breakpoints via react-responsive or react-socks
  • useWindowSize Hook - Can share this via context to avoid redundancy
  • When to split mobile vs web components

Dev tools

Storybook

Apps/Browsers

Chrome settings

  • Test performance by throttling CPU / Network performance in Chrome's performance tab
  • Simulate devices in Chrome via device toolbar - Note - You must be in simulate device mode to simulate swipe events. For example, enable device mode for a small phone and you can swipe between table columns here.

Chrome Plugins

  • Responsive Web Design Tester - (for development, hosting, and visualization) such as browser plugins, websites, and customized local webservers.

Dev Webservers

Automated Testing

Paycor Agenda

Overview

Classrooms open at 8:30 AM EST
Sessions run 9:00 AM EST- 5:00 PM EST Tues - Thurs

Lunch

Tuesday: 12:30 EST-1:30
Wednesday: 1:00 EST-2:00
Thursday: Catered! 🎉

Day 1 -Tuesday

Intro - Introductions and session structure

Modern JavaScript – Explore fundamental features commonly utilized in React apps including arrow functions, destructuring, ES modules, classes, binding approaches, promises, async/await, static fields and more. React relies upon these key features so it’s critical to begin here.

React Fundamentals – Explore what makes React different, and why it has become so popular. Learn the core React API including state, props, JSX, lifecycle methods, events, default props, keys, and tools for working with React. In this session, we learn React by building an app from the ground up, together.

Day 2 - Wednesday

React Fundamentals (Continued)

React Router – Learn how to implement rich client-side routing with clean URLs and declarative route configuration. Learn how to handle 404 pages, redirects, prompts, and url parameters.

Day 3 - Thursday

Automated testing – Begin with an untested example application and explore testing approaches by methodically adding automated unit and integration tests using Jest, Enzyme, react-testing-library, visual testing via Percy/Chromatic, and/or Cypress.

Styling – Explore the many interesting options for handling styling in a component-friendly manner including React’s built in inline-styles, Sass, naming schemes, CSS modules, and CSS-in-JS libraries. Review and compare approaches for structuring scalable CSS in a component-based world.

Advanced React (as time allows) - Explore lifting state, containers, presentation components, extracting state, conditional rendering, formatting/styling components, binding approaches, extracting child to avoid bind, compound components, branch pattern, controllable components, deep cloning, avoiding self-referential state, set state callbacks, state initialization patterns, higher order components, render props, centralized form change handling, and much more.

Feedback

Feedback form

Locations

CINCINNATI - Attendees in the Cincinnati office will be in room 118 and have a reserved seat.
FRISCO - Frisco attendees have a room reserved in 215 A/B and Adolfo Solis is your local point of contact for any logistics.
ZOOM - The session will be hosted on Zoom with video for our remote attendees and Frisco.

Time: Sep 10, 2019 08:00 AM Eastern Time (US and Canada)

Join Zoom Meeting

https://paycor.zoom.us/j/455460225

One tap mobile

+19294362866,,455460225# US (New York)

+16699006833,,455460225# US (San Jose)

Dial by your location

    +1 929 436 2866 US (New York)

    +1 669 900 6833 US (San Jose)

Meeting ID: 455 460 225

Find your local number: https://zoom.us/u/avelk9A3A

Magellan Midstream Session 3 Agenda

Review

Complete Demo app checklist

  • Async / await
  • Error handling
  • Lifting State
  • Persist state to localStorage (can mix with useLocalStorage hook)
  • Implement user role dropdown that uses reusable select
  • Implement page layout
  • Handle fast duplicate delete user clicks
  • Implement State machine for manageUsers page
  • Use promise.race to timeout a long-running API call
  • Implement login and redirect if user isn't authenticated
  • Lazy load routes and display spinner via Suspense

Modern Redux and best practices

  • Compare Redux branch to master
  • Hooks
  • Centralize state declaration

Reusable React Components

  • Slides
  • Add Storybook to project and document
  • Implement a reusable card component that accepts children
  • Export enum from button component that specifies the different types / sizes
  • Styling approaches
  • Create table component that implements as many potential states (outlined in checklist) as possible
  • Publish a reusable component to npm

Advanced React

  • Context
    • Create context branch that centralizes data. Compare with Redux
    • Use context to with best practices - Implement alert system
  • useReducer - Convert master to use this
  • useCallback - Extract useEffect logic to a function to show in action
  • useRef - Check isMounted to cancel async calls on unmounted components. Set focus on page load using imperative call.
  • Custom Hooks - See options in advanced
  • Compound Components - Implement 3 approaches and contrast

Securing Apps with Auth0

E-gineering Agenda

When

Tuesday-Thursday, August 17-19th 9:00am to 4:00pm
Suite opens at 8:30 each morning
Lunch about 11:30 🌮
Afternoon refreshments each day 🍩

Format

Mob programming something realistic! 😀

Key topics

JS fundamentals
React fundamentals
React Router
Automated testing
Mock APIs
Advanced React (time allowing)

TODO

  • Add form
  • Create about page
  • Routing / Navigation
  • Reusable components
  • Consume open source component - react-toastr for notifications on save
  • Extract add to separate page
  • Handle edge cases via conditional JSX (show message when no inventory)
  • Edit form
  • React-query
  • Context
  • Loading state
  • Automated testing
  • Load large dataset and discuss perf options
  • Use suspense and React.Lazy to lazy load routes
  • Validation
  • Error Boundaries
  • A11y
  • Derived State - Filter or sort list
  • Barrels for shortening imports
  • Handle 404s
  • Style active links
  • CSS modules and inline styles
  • Immer for immutable state management
  • Functional setState when using existing state
  • Destructuring props in func signature
  • Destructuring to streamline render calls
  • Create a custom hook (useIsMobile)
  • Uncontrolled forms via refs

Continuous Integration - CI

Tips for speed

  • Fail fast - Run cheap things first (example, check linting and rules like no-only for Cy tests first
  • Parallelize
    • Run linting and build at same time
    • Then run tests for all projects in parallel
    • Can go even farther like Cypress dashboard and intelligently parallelize
  • Run the prod version of the app
  • Remove unused packages from package.json
  • Run reusable Cy tests against prod storybook build
  • Move storybook to root and test against a prod storybook build
  • Try Yarn with workspaces
  • Quiet reusable Storybook webpack build output
  • Use Lerna, Nx, or pnpm
  • Run Cy against the prod build to speed responses, test prod build, and avoid needing to compile the app twice on CI 😎
  • Assure each test, build, lint, and process runs only runs once
  • Cache Cypress image or use the official Cypress Docker images with the included test runner and browser
    to eliminate install
  • Avoid running webpack-bundle-analyzer on CI

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.