Intro to React Workshop

Richard Lindsey     @Velveeta

Lesson 1

Component Types

Class-based Components

  • React's first, and probably still most widely-used form of authoring components
  • Makes use of ES6's class syntax, with the extends keyword
  • Provides a built-in set of lifecycle methods to help deal with varying render stages

Class-based Components

import React from 'react';

class HelloWorld extends React.Component {
  componentDidMount() {
    console.log('I mounted!');
  }
  
  componentWillUnmount() {
    console.log('I am about to unmount!');
  }
  
  render() {
    return <div>Hello World!</div>
  }
}

export default HelloWorld;

Functional Components

  • Introduced in React v0.14
  • Originally intended to be used for traditionally "dumb" or stateless components
  • Have become much more powerful with the new hooks API
  • Have no concept of rendering stages outside of what the hooks API provides

Functional Components

import React from 'react';

const HelloWorld = () => <div>Hello World!</div>;

export default HelloWorld;

Lesson 2

Component-based Development

Component-based Development

Traditional Development

  • Building applications by pages
    • Difficult to reuse code modules
    • Very little modularity
  • Building applications by services
    • Easier to to reuse code modules
    • Indirection can become a problem
    • Services are cohesive unto themselves, but lose application context

Component-based Development

Development via Components

  • Building applications by layers of components
  • Components become natural encapsulation boundaries
  • Component-based applications tend to read more naturally
  • Code reuse is as simple as dropping a component into a view
  • UI views can be written as components
  • Services can be written as components
  • Data stores can be written as components
  • ... can be written as components!

Lesson 3

Compound Components

Compound Components

  • Declaratively apply behaviors to children
  • Declaratively apply transformations to children
  • Help to decouple behavioral logic from children
  • Can be used to apply additional props to children

Compound Components

  • Relies on React.Children and React.cloneElement functions
  • React.Children.map to iterate over children
  • React.cloneElement to create a copy of the virtual DOM object for a child, with transformed or additional props
  • Remember to pass along existing child props
  • Risk of prop name collisions with this method

Lesson 4

Controlling Form Components

Controlling Form Components

Controlled Components

  • Requires onChange handler
  • Similar to Angular's two-way binding
  • Allows state to drive UI exclusively
  • Realtime validation feedback

Controlling Form Components

Uncontrolled Components

  • Uses alternative handlers (onBlur/onSubmit/etc)
  • Requires refs to harvest field values
  • Requires manually syncing values to other consumers
  • Risk of UI getting out of sync with state, if using state

Lesson 5

State vs Props vs Context

State vs Props vs Context

State

  • For self-managed component aspects
    • Form element values
    • isOpen for things like Dropdowns
  • setState function for value updates, which triggers a render update cycle

State vs Props vs Context

Props

  • For externally-managed component aspects
    • data for Grid components
    • options for Select components
    • Various callbacks for value updates
  • Render update cycles are automatically triggered when any external prop changes, as long as the render cascade hasn't been stopped by something like shouldComponentUpdate

State vs Props vs Context

Context

  • For externally-managed component aspects in deeper component trees, to avoid prop-drilling
    • Can function as a mini data store for a vertical segment of an application
    • Various callbacks for value updates
    • Provider/Consumer components created via React.createContext, can also be used with useContext hook
  • Render update cycles are automatically triggered when any context value changes, as long as the render cascade hasn't been stopped by something like shouldComponentUpdate

State vs Props vs Context

  • Feel free to mix and match all 3 for different scenarios
  • If using state that's initialized from props, and updated when props change, consider only using props
  • Data updates should propagate down the component tree via props, and back up the component tree via callbacks
  • State should ideally live at the lowest possible point in the component tree where it's needed amongst any siblings
  • Avoid calculating derived values for state/props/context from functions that return new references each time, e.g. array map/filter operations, unless you're memoizing somehow

Lesson 6

State Management With Redux

State Management With Redux

  • Helps prevent prop-drilling by subscribing to any global state changes exactly where you need them
  • Composable nature is nestable as shallow or as deeply as you need it to be
  • Uses fluxy concepts like dispatched actions to control data updates
    • Single, global data store, in contrast to flux's multi-store paradigm
  • Store structure does not need to mirror application structure
  • mapDispatchToProps offers a simplified 2nd form

State Management With Redux

  • Avoid storing non-serializable data
  • Avoid data duplication
    • Either store raw records for use by multiple consumers with different transformations, or
    • Store pre-transformed data in dedicated namespaces, and pull that data, ready to use
  • Avoid connecting too few or too many components, as too few leads to increased prop-drilling, and too many adds overhead on update cycles
  • Avoid the mergeProps option, use a container component with self-bound functions instead

Lesson 7

Memoization

Memoization

Memoizing Components

  • React.PureComponent base class for class-based components
    • Automatically implements shouldComponentUpdate
    • Only uses a shallow compare check against props and state, so context updates could potentially get blocked at this level
  • React.memo for functional components
    • Uses a similar shallow comparison check against incoming props, so could also potentially block context updates

Memoization

Memoizing Data

  • Allows for caching of results from expensive operations
  • Allows for consistent object and array references between render cycles
  • Tradeoff is increased memory footprint
  • Make sure your cache-busting strategy is solid, or else you risk stale component data
  • Popular options: reselect, re-reselect, useMemo hook

Lesson 8

Imperative to Declarative

Imperative to Declarative

  • Design your components as granular API's
  • Props should define UI or behavioral intent
  • Lifecycle methods and hook dependency lists allow for setup and teardown, updates, and other timing concerns
  • Literally any API can be wrapped in a component for a declarative drop-in, which will be fully aware of application context, and allow natural prop cascades to govern updates

Lesson 9

Testing React Components

Testing React Components

  • Test behaviors, the way your component is intended to be used
    • E.g. test clicks, value updates, focus/blur, etc
    • Use spy functions to assert that relevant handlers are called properly on user interactions

Testing React Components

  • Test UI side-effects, the way your component is intended to be consumed programmatically
    • Update values and verify that the corresponding UI output is present
    • Update values and make sure downstream props are updated accordingly (for compound components, etc)

fn.

Day 1 complete, congratulations!

Richard Lindsey     @Velveeta

Made with Slides.com