Landing

Hello 👋

We're here since September 2017 building e-commerce web apps

Goals 🏆

Get hooked to React

Build an app to keep track of your favourite movies and tv shows

Before we start

Join us 💬

tlk.io/react-workshop

React

React is a declarative, efficient, and flexible JavaScript library for building user interfaces

It let you compose complex UIs from small and isolated pieces of code called “components”

JSX

const element = <h1>Hello, world!</h1>;

Template language with the full power of JavaScript

Virtual DOM

Programming concept where a “virtual” representation of a UI is kept in memory and synced with the “real” DOM

The process is called reconciliation

Components and Props

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

State

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "World" };
  }

  render() {
    return <h1>Hello {this.state.name}!</h1>;
  }
}

Hooks

Hooks are a new addition in React 16.8

Functions that let you “hook into” React features

For example, useState is a Hook that let you add React state to function components

useState

Returns a stateful value and a function to update it

const [state, setState] = useState(initialState);

Rules of Hooks

Only Call Hooks at the Top Level

Only Call Hooks from React Functions

👮‍ eslint-plugin-react-hooks 🚔

Challenge 1

Build search input with a button and a text below with the query, all this using setState

useEffect

Accepts a function that contains imperative, possibly effectful code

useEffect(() => {
  doSomething(a, b);
}, [a, b]);

Fetch API and Promises

fetch("some-url")
  .then(response => response.json())
  .then(resolve, reject)
  .catch(error);

Challenge 2

Add useEffect to fetch the search results

useEffect

useEffect(() => {
  doSomething(a, b);

  return () => {
    cleanup();
  };
}, [a, b]);

Challenge 3

Implement the closing detection for modals with a useEffect with a cleanup

useMemo

Returns a memoized value

const memoizedValue = useMemo(() => {
  return computeExpensiveValue(a, b);
}, [a, b]);

Challenge 4

Memoize the cards in the search result

useCallback

Returns a memoized callback

const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

useRef

Essentially works as an instance variable

const refContainer = useRef(initialValue);

Challenge 5

Convert the value of the search input into a ref

useRef

A ref can be passed directly on elements

<div ref={someRef}/>

// there's a difference 🚨

<Component ref={someRef}/>

forwardRef

const Input = forwardRef((props, ref) => {
  // ...

  return <input ref={ref} {...props} />;
});

Challenge 6

Use refs directly on elements

 

☕️ ⏰

Context

Way to share values between components without having to explicitly pass a prop through every level of the tree

<Context value="Hello World!">
    <...>
        <MessageComponent />
    </...>
</Context>

useContext

Obtains a value in context by its type

const value = useContext(ContextType);

Challenge 7

Instead of prop drilling the API configuration create a shared context and consume it using useContext directly

Custom Hooks

Functions that use other hooks

Challenge 8

Implement loading and error state in SearchResults with only state

Reducer

A function that receives a state and an action and returns a new state

const newState = reducer(state, action);
const newNumber = reducer(0, { type: 'add', value: 2 });

Reducer

function reducer(state, action) {
  switch (action.type) {
    case "add":
      return state + action.value;
    case "subtract":
      return state - action.value;
    default:
      return state;
  }
}

useReducer

Returns the current state paired with a dispatch method

const [state, dispatch] = useReducer(reducer, initialState);

Challenge 9

Convert the loading and error logic to a single useReducer

Redux

Reducers shared in context

const { store } = useContext(ReduxContext);
const { getState, dispatch } = store;

Challenge 10

Move the reducer inside SearchResults into a shared context

Challenge 11

Move the fetch inside the SearchContextProvider

useLayoutEffect

The signature is identical to useEffect, but it fires synchronously after all DOM mutations

useLayoutEffect(() => {
  doSomething(a, b);
}, [a, b]);

useImperativeHandle

Customizes the instance value that is exposed to parent components when using ref

useImperativeHandle(ref, createHandle, [deps]);

 

If you'd like to continue...

Sources

React Docs

Dan Abramov's Blog

 

Thank you 🙇‍

tinyurl.com/getting-hooked-to-react