Redux Flashcards
What will we learn?
everything we need to know to build real, complex apps with Redux
work on a real bug tracking app with a node backend
by end of course, know and understand Redux inside/out

What is Redux?

A state management library for Javascript applications
doesn’t care what library we use for UI development
instead of scattering app state across UI
store state in a single JS object (store)
single source of truth
like a “database” for front end
components get state from store
data is updated in a single place
can see how data changed, why, when and where it came from

Why do we need redux (state managment)?

complex UI, need to keep in sync
data updates from backend request, user interaction, etc. changes must be reflected immediately

What are the pro’s of Redux?
debugging
transparent state changes
can reload state, view actions and see UI changes
cache/preserve page state
entire app state available on client in JS object (store)
don’t have to reload data from server
centralized state
data is available in one place, accessible by all parts of UI

When is redux NOT right for my project?

must consider constraints and problem domain
A real software engineer is an active problem solver
not every application requires Redux
DON’T USE
if load data and display statically (not changing)
if it’s a tight budget
if the UI is very simple
**it will be complex and slow you downl
What is functional programming?

Redux is built on top of functional programming
A good background is critical to building redux apps
One of the programming paradigms
Each paradigm has rules for how to structure code to solve problems
invented in 1950s
decomposing a problem into small, re-usable functions
can compose functions to build complex pipelines
Pros
can run in parrallel
exploit multiple cores
Benefits:
more concise
easier to debug
easier to test
more scalable

Why are functions first class citizens in Javascript?
can treat them like any other variables
assign them as variables
pass them as arguments
return them from other functions

What are higher order functions?
a function that…
takes a function as an argument
returns a function
both!
Why?
instead of working on strings, numbers or booleans
it goes higher to operates on functions
What is the problem with this approach?

expression is read right to left
trim, make lowercase, wrap in div
so many parenthesis
Soln?
What is currying?

Solves this problem:
functional pipeline
function in line requires two parameters (fns)
only have one fn as parameter
How?
allows us to take a fn with N arguments
convert it to an fn with 1 argument
What?
instead of separating args with commas “,”
separate with ( )

What is the challenge with this code?

wrap function expects two arguments
if we pass type as argument
pipeline will throw an error
Why?
it requires a function as argument, not string
Soln?
currying

What are pure functions?

a function that given the same args, produces the same result

NOT:
random values
current date/time
global state
Why?
These change
Redux?
reducers must be pure
other fns don’t have to be
What are the benefits of pure functions?

Self documenting
everything a fn needs is clearly identified in parameter signature
easier to test
no global state
concurrency
because not using global state
can run in parallel
cacheable
can store result in cache and use in future
useful in programs with intensive computations
if we know certain computations produce same results
can optimize by storing in a cache

What is immutability?

Goes hand in hand with pure functions

once we create an object, cannot be changed
must take a copy and change that copy
Ex. Strings are immutable, create copy, original string not affected
Objects and arrays can be modified directly, not immutable
Does “const” prevent mutability?
No
it prevents re-assignment
common misconception
Ex. cannot re-assign book to another object

What are the benefits of immutability?
Predicatable apps
if we call a fn, pass an obj
obj won’t get changed, no suprises down road
Fast change detection
React needs to know when changed
creating a new obj, stored in memory
React compares objects by references
this is fast operation
in contrast, without immutability
React has to compare all properties in two objects to see it’s changed
slow operation
Concurrency
can run in parallel
not going to affect something that affects system as a whole

What is the problem with this code?
Spread operator does a shallow copy
nested objects are copied by reference (not value)
Ex. Both person2 and person2copy have the same reference to “address” in memory (not copied by value) copied by reference
Soln?
Do a deep copy
set a new nested object using spread operator

How do we copy an array and insert a number at a specific location?

How do we update an array using immutability?
Hint:.map ( ) method

How do we enforce immutability?

By default, Javascript doesn’t do this
Why?
It’s a multi paradigm language
it doesn’t enforce immutability without libraries
Soln?
Libraries that enforce real immutability
Different people love different tools
Immutable.js (by Facebook)
Immer (becoming trendy, Mosh loves it)
What is immutable.js?

Hint: npm i immutable
a library by Facebook
provides a bunch of immutable data structures
*Mosh prefer’s another library
How?
instead of a plan JS object
use one of the datastructures from this library
Problems?
have to learn a new API
cannot access obj properties with . or [] notation
have to use .get( ) method
integration with other libraries
hard to integrate with other libraries that expect plain JS objects
have to call .toJS( ) method to convert to plain JS objects

What is Immer?
Hint: Immutability library (npm i immer)
almost as popular as immutable.js

Pros
writing code as if mutating objects but actually not
better than using spread operator (get’s nasty with nested objs)
Write code to solve this?
Hint: function composition


What are the three building blocks in Redux applications?
Store
single JS Object that includes application state
Actions
plain JS Objects that represent what happened
aka events (what happened)
Reducers
one or more functions responsible for updating a slice of Store (single JS object)
aka event handlers or processors
pure functions, don’t mutate arguments, no side effects

How do Redux building blocks work together?
Action object is dispatched to Store
Store calles the Reducer
Ex. When user performs an action (add item to shopping cart)
Create an Action item and dispatch it
Store object has dispatch method that takes an action
Store object forwards action to reducer
Reducer is not called directly, we only work with the Store
Store is in charge of calling the reducer
Reducer computes new state and returns it to Store
Store sets state internally and notifies UI components directly

Write code to solve this?
Hint: immutabile objects / arrays


What is a store?

simple API interface
JS Object
includes properties:
.dispatch
method for dispatching actions
.subscribe
method for subscribing to store
get notified everytime state of store changes
used by UI layer
.getState
get current state of store
to change state of store, have to dispatch an action
Store object has dispatch method that takes an action
Store object forwards action to reducer
Reducer is not called directly, we only work with the Store
Store is in charge of calling the reducer
Reducer computes new state and returns it to Store
Store sets state internally and notifies UI components directly

What is a reducer?
A function that takes current instance of the store (JS state object) and returns an updated store
Returns?
using spread operator or immutable library to return an updated store
How?
supply store and an action as arguments
action is a plain JS object describing what just happened
lets reducer know what to update in store (JS state object)
Many?
each reducer is responsible for updating a specific part of the store
Ex. Many departments in a store, each department has a manager

What is an action?
argument to the reducer function
tells reducer what properties in store to update
actions that happen in our applications (events)
Ex. UserLogin, UserLogout
based on the type of action, reduce will know what parts of store (state) to update

Why is redux designed this way (ie. to dispatch actions)?

Dispatch is like entry point to store (JS state object)
every action is sent through same entry point
central place to control what should happen every time a user performs an action
can log every action
can implement undue/redue mechanism

What are the four steps to follow when building a redux app?
Design the Store
What do you want keep in the store?
Define Actions
What are actions user can perform in application?
Create Reducers
Take an action, return updated state
Setup Store based on Reducer

How would we design the store of a real world application for tracking bugs?
An object with two properties (slices):
bugs - list of bugs
current user - initially null, then set when user login
*two slices, requires two reducers

What actions would a user perform in a real bug tracking application?

An action is just a plain JS object that describes what happened
must have a type property (required)
Payload property contains minimum data including description or ID for an action
description can be any serializeable data type
because description must be able to store on disk, reload later
use strings so we can view description of what happend
can store form data in description, etc. (bug type, who logged, etc)
ADD_BUG
bugAdded
common conventions for type in Redux apps
(vs. numberss not descriptive)
Actions (events):
Add a bug
Change status of bug
filter list of bugs
change sort order
Mark as resolved
Delete a bug

How do we create a reducer?


What’s the problem with this code?

In real app
payload contains minimum required information
Ex. bugAdded -> only need ID, not description too
Use immutable library in real app (not spread operator)
How do we implement this logic using switch and case?

Reducer is a pure function
everything it needs is passed as arguments (only dependencies)
given the same input, returns same output
doesn’t touch DOM elements
doesn’t work with global state
No API calls

How do we create a store?
Hint: single JS object that contains app state

import {createStore} from ‘redux’;
import reducer from ’./reducer’;

How do we create a store?


How do we dispatch an action?

In real app,
when user clicks add button
we are going to dispatch an action (raise an event)

How do we subscribe to the store?
Hint: get current state of store everytime state changes

store.subscribe ( )
takes a fn
called everytime a change happens in the UI
UI components should subscribe to store so they are notified when changes happen

What does the subscribe method return?

a fn for unsubscribing from store
possible user navigates away from current page
in new page, don’t have UI component
don’t want to be subscribed to a UI component that is not visable
this can create memory leaks

What is the redux workflow?
Hint: code example

When we dispatch an action
store.dispatch( { action } )
store calls reducer
state = reducer (state = [] , action)
store gives reducer current state in store and action passed to store
reducer returns a new state to store
based on logic / type of action (switch case)
notifies subscribers of changed state

What’s the problem with this code?

we hard coded the action type (string)
if we change the action type name later
will have to change in multiple places or get a bug
Soln?
create a file actionTypes.js

What’s the problem with this implementation?

dispatching an action is not easy
have to type the entire structure
if re-using action in multiple places, will duplicate code
Soln?
Create a fn that creates action object

How do we implement BUG_RESOLVED?

Create the action first
plan JS object w/ type + payload
store.dispatch ( action )
Create the reducer next
returns an updated state object to store
store.subscribe ( observer ) notifies observers of state change
Pass action to store
store.dispatch ( action )

What is a good idea when learning a new tool?
Think about how that tool works and how it was built
Mosh is going to show us how Redux works / is built!
We are going to build Redux from scratch
How do we build the store from scratch?
state property is a private property
How do we create a private property?

How do we implement the dispatch method in our custom store?

Call the reducer to get the new state
Notify the subscribers

How do we implement the subscribe method from scratch?

How do we use Redux Dev Tools?
Hint: A powerful tool for debugging redux applications

We need to pass extension to createStore ( ) method
Add:
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
A powerful tool for debugging redux applications

What is the log monitor?
Hint: Redux Dev Tools
a plain list of actions that have been applied
Action + state after action applied

What is the Chart field?
Hint: Redux Dev tools
show actions in a visual way
Ex. DollarShaveClub’s React/Redux Actions Chart

What is the inspector field?
Hint: Redux Dev tools

diff shows you how tab has changed

How can I identify the source of problem in my Redux app?

using Redux Dev Tools:
1. Look at actions dispatch - ensure right action was dispatched, if not dispatch that action
- Check to ensure action was carrying the right data, if not modify action creator (responsible for action)
3. Check state tab - ensure state was updated properly, if not modify reducer function (responsible for state)

What is the test tab?
Hint: Redux Dev Tools
Generates basic boiler plate for testing action

How do we enable tracing in redux dev tools?
Hint: $ npm i redux-devtools-extension

Where in source code a given action was dispatched
import in store module
replace window._REDUX_DEVTOOLS_EXTENSION
with devToolsEnhancer()
call this function, get a function returned
returns a storeEnhancer function

How do we configure Redux Dev tools tracing function?

maps line of code in bundle and source code
add devtool: “source-map” to webpack.config.js
app.js.map
settings -> code editor -> vsCode -> pwd (working directory path)
/Users/kingarsalon/Desktop/GitHub/redux/Source Code/redux-starter

What is exporting the store?

Very powerful feature of redux
Can store all interactions of user with our application in a single JSON file
then, reload the state from that JSON file later
Why?
Easy debugging
don’t have to launch application and follow all steps leading to a bug
can simply reload app in same state as user
look at all actions
look at state updates
Log Rocket does this for every user in production
download from Redux Dev Tools
upload into Redux Dev Tools
What is one of the complaints about Redux?

It makes you write so much boiler plate code
So…
Mosh is going to show us
How to write clean, concise redux code

How do we structure our redux code in a clean way?
Hint: completely isolate from UI code

UI and state management are two different concerns
Move all redux code into a separate folder
next, group all files by feature (subdomain)
each subdomain should contain it’s own:
actions
actionTypes
reducers
Why?
could have hundreds of actions
break down into small subdomains or bounded contexts
Ex. Auth domain
all about authorization and authentication
actions - login, logout, changePassword
Ex. Bugs domain

What is the dux pattern?
Hint: re_dux_

a bundle of actions, actionTypes and reducer for a specific domain
Why?
instead of having separate files:
actionTypes.js, actions.js, reducer.js
combining all for particular domain into one file
makes it easier to edit, update redux domain
any changes to that domain, go to one file

What rules must we follow when implementing the dux (redux) pattern?
reducer
has to be a default export in the module
action creators
must export individual action creators

What is the Redux Toolkit?
Hint: npm i @reduxjs/toolkit

Redux team officially recommends Redux Toolkit
to simplify your code
library provides a bunch of helper functions (utility functions) to simplify redux code
How can we refactor this code?

npm i @reduxjs/toolkit
configureStore ( )
wraps createStore ( ) fn and development tools
includes:
reduxDevTools
we don’t have to manually import this anymore
utility functions to help with calling APIs
able to dispatch asynch actions (calling API)
without this function, will have to apply middleware to dispatch async functions for calling APIs

How do we create actions with less boiler plate?
Hint: npm i @reduxjs/toolkit

every action creator returns an object
can use reduxtoolkit to simplify the code
createAction( )
returns an action creator
import { createAction } from “@reduxjs/toolkit”
How do we refactor this code using Redux toolkit?
Hint: refactor Action creators

createAction ( ) returns an action creator
call fn and pass payload (see index.js)

What does the createAction ( ) fn return?
Hint: createActionCreator( )

utility function from react-dev-tools
createAction ( ) returns an action creator function
should be called createActionCreator ( ) !
returns an action creator function
pass args to create an action object

How can we refactor this reducer using Redux toolkit?

don’t have to write immutable updates to state
can replace switch-case statements
under the hood, uses immer
code we write in reducer is automatically converted to immutable code!

What is the problem with this code?

The string we are passing to the actionCreator is hard coded
This dependency breaks the reducer when calling createReducer and passing an action with a hardcoded name that was changed
soln?
instead of hardcoding the name by passing a string arugment
can use [] to dynamically compute the action name (property)
action object contains a method that returns type property of the action
What is the create reducer method take as arguments?
Hint: redux toolkit createReducer ( )
createReducer ( ) two method arguments
Arg #1
initial state, alias that matches slice of state to be changed
Arg #2
{ pass an obj } - that maps
key = action names value = fns
event => eventHandler
What is Creating Slices?
Redux toolkit
createSlice( ) function
creates an action and a reducer together
cleaner, simplier code
createSlice ( ) method
takes a configuration object
with properties :
name:
initialState:
reducers: {
action: actionHandler}
How do we refactor this code?

Hint: createSlice( ) redux toolkit
use CreateSlice ( ) method
internally the reducer property function calls
two functions - createAction ( ) , createReducer ( )

What is the createSlice ( ) method?

Redux tool kit
takes a configuration object
pass action as key (event)
pass reducer as value (eventHandler)

How do we use the createSlice ( ) method to write clean, beautiful redux code?

don’t have to explicitly create actions and actionhandlers
createSlice ( ) creates both for us

What is a slice?

Redux Toolkit
creates action using createAction ( )
creates reducer using createReducer ( )
allows us to write mutable looking code
converts to immer (immutable code)

Okay to have local state in our UI components or do we have to put all our state into redux store?
Two approaches to organizing data in redux apps:
- Global Data Only - in Redux store
if multiple components use data, store in Redux store
Ex. eCommerce - put user and shopping cart (global data) in redux store
everything else in outside of store
Mosh is not a fan because it doesn’t allow us to get all redux benefits
Using redux in small part of application
no time travel debugging
no testable code
no caching and persistence
Don’t use Redux in a small app with simple data flows
Therefore…
if all we do is use Redux to share global data, it’s a waste, better to use Context Objects to share global data in React
- Put everything in store - single, unified way to access data, comes at a cost
Benefits:
more consistent
more maintanable code
store as a cache
easier debugging using redux dev tools
code becomes easier to test
Mosh favors this approach

What are the benefits of putting all the UI data in a redux store?
Hint: Exception - form state data
Don’t store form state data in Redux
Put everything in store
single, unified way to access data, comes at a cost
Benefits:
more consistent
more maintanable code
store as a cache
easier debugging using redux dev tools
code becomes easier to test

Why is it not a good approach to only store global data in Redux and other UI data locally?
Global Data Only - in Redux store
if multiple components use data, store in Redux store
Ex. eCommerce - put user and shopping cart (global data) in redux store
everything else in outside of store
Mosh is not a fan because it doesn’t allow us to get all redux benefits
Using redux in small part of application
no time travel debugging
no testable code
no caching and persistence
Don’t use Redux for small data apps
Why should we not store form state in Redux store?
Hint: Store form state locally in components

Reasons:
- Temporary values in a form
have no impact on other UI until user submits form
okay to populate a form with data from store
don’t want to update the store as the user is typing
no value in keeping temporary data in the store
update store only when user submits
- Too many dispatches
we shouldn’t dispatch an action on every key stroke
causes performance issues
makes debugging more challenging
Ex. 50 actions as user was typing full name
Soln?
Store form state locally in components

What is the best way to structure our store?
Hint: use an object
Use an object
each key represents an ID
each value represents an object
Benefits:
Can quickly lookup object by ID (accessing property)
this is a very fast operation
very clean and fast lookup
doesn’t preserve order
vs.
using an array, first find index (slow operation, iteration)
What are the Pros and Cons of structuring the Redux store using an object?
Pros
allow fast lookup (hashmap, key-value pairs)
if you need fast lookups, use an object
Cons
doesn’t preserve order
cannot re-order properties in an object
if you need ordered data, use an array
Or use a combination of two!
Ex. using an object to store bugs, array to store bugID’s

How should we structure our store?

each slice represented as an array
wrap slices in a parent slice called (nested)
another high level slice for user (name, id , authtoken)
another high level slice called UI (state specific for components)

How can we create a store with multiple slices (multiple reducers)?

combineReducers ( ) from redux
combines our reducers into a single reducer we can pass to our store

What are we doing essentially by nesting slices under entities?

combining reducers
creating a hierarchy of reducer functions
root reducer passes action to entities
entities reducer passes actions to children reducers
Main Idea?
multiple reducers can handle same action
each reducer is responsible for updating only one property in the store
this keeps each reducer in a single responsibility
What does normalization mean?

We should not duplicate data in our store
remove nested data by replacing with identifiers
connect related data using identifiers
aim to keep data as flat as possible
get rid of duplicates, using identifiers
No nesting
can look up object by objectID if neccesary
Ex. project object in a few places of store - update name, have to update every instance of data or will have inconsistent data

What is the library normalizr?
Hint: npm i normalizr
If your app talks to an API
received de-normalized, hierarchical data from server
use normlizr to normalize your data

How do we compute derived data from data in our store?
Write a query using method chaining after
.getState( )
A derived data element is a data element derived from other data elements using a mathematical, logical, or other type of transformation, e.g. arithmetic formula, composition, aggregation.

What is the problem with this approach?

In real application
logic for computing derived data can be complex
logic may be in a few different places
without a deriving class (selector)
these objects will break with changes
Soln?
Selector fn
takes state, returns a computed state
What are selectors?
Hint: computed state functions (query state logic)

functions that return computed data
take state as an argument
return a computed state
Naming conventions:
getUnresolvedBugs( ) *
mosh’s favorite, it’s shorter
unresolvedBugsSelector ( )
selectUnresolvedBugs ( )
Benefits:
single place to modify function
can re-use in multiple places in application

What is the problem with this code?

Hint: .filter ( ) method returns a new array
$ npm i reselect
$ npm i reselect
createSelector ( ) method returns a memoized selector (cacheable)
selector won’t execute logic if it’s in cache
will return value from cache
.filter ( ) method returns a new array
we don’t want state to re-render everytime we query the store
Soln?
Memoization
memoize this function
a technique for optimizing expensive functions
can build a cache of input / output
before executing expensive logic, look at cache
if operation has previously been run, get data from cache
What is createSelector ( ) ?
from npm i reselect
a function that creates a memoized selector
Two arguments:
selector - get’s state and passes it to results function (query logic)
results function - selector passes state, logic is executed if value not in cache
if value is in cache, results function will get data from cache
How do we assign a bug to a user?


What is middleware in redux?

a curried function with three parameters
store => next => action
an advanced topic in Redux
building block that allows us to do side effects (like calling APIs)
How?
add functions that are executed everytime an action is dispatched
called middleware
peice of code that is executed after it’s dispatched, before reaching root reducer
Why?
Calling APIs
Error Reporting
Analytics
Authorization

How can we parameterize a middleware function?


How can we change our .dispatch ( ) method in our store to accept functions?
Hint: allows us to make Async API calls

By default
store.dispatch ( ) takes an object with type property ONLY
will give errors if we try passing a function or obj without type property
Soln
create a middleware function called func.js
handles calling the function if store.dispatch ( ) is passed a fn
allows us to make async API calls
How?
logic - if typeOf action is function, call function
otherwise, pass to next middleware or reducer (if no more middleware)
Why?
passing a function is used call asynchronous APIs that return promises
Redux Toolkit
creates this middleware func (thunk) for us!
Use redux toolkit

What is the problem with this code?

In index.js have access to store.dispatch ( )
in other parts of our application we can not dispatch functions easily
if we try to import the store in other parts of application, a new store is created
How can we dispatch functions using the store in other parts of our application?
Soln?
pass a reference to the dispatch function when dispatching a function

Why do we need to call APIs in our redux applications?
Hint: Getting or Saving Data with Backend
Almost every front end application needs
to talk to a backend for getting or saving data
Very important topic
Really important principles
Change how you think about software design
Where should we put code with side effects (API calls, global data, etc.)?
Hint: Action creators

In action creators
Why?
Reducers must be pure functions
this makes them easy to test
no API calls
no DOM manipulation
How?
With Thunk middleware (dispatch functions)
can return a function from an action creator
re-write actionCreator ( ) fn using => syntax
with dispatch and getState can do more processing

How can we refactor this action creator?
Hint: use arrow fn syntax

action creator is a fn with no parameters
returns a function with (dispatch, getState) as parameters
returns some logic
this is currying in action

How do we call an API using our action creator?

Three things (basic pattern):
- Call API - axios, fetchApi, any library (async)
returns a promise
- Dispatch success action - promise resolves
reducer catches and updates state
Resolved: dispatch (success)
- Dispatch error action - promise rejects
Rejected: dispatch (error)

What are the naming conventions for actions that return functions for calling APIs?
Hint: Past tense vs Present tense
Present
GET_BUGS_REQUEST
GET_BUGS_SUCCESS
GET_BUGS_FAIL
Past tense
bugsRequested
bugsRecieved
bugsRequestFailed

What’s the problem with this pattern for calling APIs using actionCreators?

Very repetative
as we implement more features in App
each time we call an API
have to follow three steps
write code for calling, dispatching, error handling
chaining then and catch methods
or try catch blocks
Soln?
Middleware
can implement this pattern in middleware

What kind of action object should our api middleware be able to handle?

serializable
passing strings vs functions

What are the problems with this implementation?

hard coded action type’s
one in middleware
one in action
soln?
create an actionCreator( )
Inconsistent naming
better to have names match
Soln?
refactor
action creators!
access .type property in middleware fns

How can we restructure our store?
Hint: [] vs { }

restructure from array to object data type
add properties :
loading
display loading to user
lastFetch
used to determine cache integrity (up to datedness)

Why should we not have these details in our UI layer?

have to repeat this action creation in multiple UI places
Ex. drop down, bugs page, etc.
breaks with changes
have to update multiple lines of code
Soln?
store.dispatch(loadBugs() )
details of endpoint, action, etc. abstracted
How do we design a feature to handling loading while app is getting data from server?
When call server
set loading to true
in UI show/hide spinner
Steps:
1. Define new action
bugsRequested in bugs slice automatically creates an action
2. Define new reducer
sets loading prop to true
fn in slice
3. Change middleware
generat action based on property (onStart) by loadBugs ( ) to middleware
dispatch new action before making an API call

How do we handle the situation in which something goes wrong?

create a new action and reducer
that set’s the loading property to false if an error occurs

How do we solve this problem?
Hint: npm i moment

Don’t want server to call API second time in 2 seconds

Soln?
Caching
re-write loadBugs action creator to return a fn that includes dispatching new action
stamps currentTime
moment ( ) library returns current date time
can compare to current time if
in real app, extract logic into re-usable component
How do we save data to the server?
Hint: Http Post request

Soln?
dispatch API call, let API middleware handle everything
loadBugs ( ) is dispatching an API action (bugs.js)
addBug ( ) dispatches an API action (bugs.js)
consume using .dispatch ( API action)
Why?
Same steps as making an API call:
Make an API call
dispatch (success)
dispatch (error)
just let API middleware handle this logic

How do we resolve a bug?
create an actionCreator to create an API action
let API middlware handling calling server, handling errors
updates server
updates store

What’s the problem with this code?

exporting bugAdded, bugResolved, etc.
only place they’re used is in bugs.js module
Soln?
Don’t expose to outside
other modules cannot use internals of bugs module

What is Mosh going to show us around testing?
Right way to do testing in Redux applications
there is a lot of bad information out there
Short / practical introduction to testing (included)
lot’s of misconceptions around automated testing
What is automated testing?

Hint: npm i
jest
@types/jest
@bale/core
@bale/preset-env
babel-just
Writing code to test our code
can run hundreds or thousands of tests
far faster and easier than manually testing functions
always an element of manual testing
there is a balance between automated testing and manual testing
Unit Test
tested without external dependencies
fast to run, uses mock functions
focus of this course** (unit testing)
run during production
Integration
test app with external resources
slower but give greater confidence
run at certain phases like committing code, getting production ready
End-to End
launch application, drive through UI
slowest, most fragile tests

How do we write tests?
Hint: Write social tests not solidarity tests

Define a group / suit of tests
describe ( ) function
first arg - name (group)
second arg - fn called by jest (includes test fns)
Name should be meaningful
“isEven should return true if given an even number”
function to define test
it ( ) given by jest
first arg - name of test
second arg - test fn (contains code of test)
Call function under test
call function you’re testing
create an expectation (make an assertion)
expect ( )
fn provided by jest
Use a matcher in assertion
.toEqual ( ) , NaN, contains, etc

How can we unit test a redux application?

Hint: Solidarity tests are poor way
as long as no external resources, it’s a unit test
Solidarity (lonely) tests
test individual building blocks in isolation
write separate tests for
actions creators, reducers, middleware
POOR WAY
Sadely, most books / courses teach this way
Why?
Coupled to implementation
Know too much about how app is structured
structured to implementation
when our implementation changes, tests break
slow us down, re-writing tests!
Soln?
Social tests
implementation details not important, study behavior

What should our unit tests test?
Hint: test behavior NOT implementation

Behavior of application
NOT implementation
Ex. Test timer or microwave
don’t care how current goes around, etc in microwave
only care about pressing start button
test behavior not implementation
solidarity tests are testing action creators, reducers, etc.
They know too much about implementation details
They’re too connected to implementation
can test a lot of building blocks, but doesn’t show if app work
Redux is about changing state of store
building blocks ensure app state changes accordingly
test all building blocks together!
Soln
Social Tests

What are social tests?

Proper way to test redux applications
dispatch an action, check state
what happens under hood, irrelevant to tests
Tests that involve multiple functions / objects working together
Benefits:
less fragile
don’t break
more reliable
test behavior of application
don’t care if an action, calls another action
don’t care if middleware catches an action, dispatches another
don’t care about reducers and how we combine them

Are solidarity tests evil?

Absolutely not
they’re great and have their own uses
if building block is complex
test it in isolation
Redux building blocks are simple
they don’t have algorithms or complex logic
no logic
action creators return an action
reducers return state
How do we write a solidarity test for adding a bug?

action creator addBug
returns an action object that represents API call
have to call it, look at object
API middleware takes object, on success
dispatches another action
reducer takes action, updates store

What is the problem with writing solidarity tests?

If we change the implementation details, test fails!
Solidarity tests:
break easily
don’t give confidence

What’s the problem with solidarity tests?
Hint: Doesn’t test behavior of application

They don’t test application behavior
Ex. api middleware commented out, test still passing

How can we write a social test?

A test that excercises multple building blocks (units) together
doesn’t break with updated implementation
behavior is not changed
beauty of social tests
Ex. Change addBug ( ) implementation to omit API middleware

How do we convert this test from an integration test to a unit test?
Hint: npm i axios-mock-adapter -D

npm i axios-mock-adapter -D
creates mock axios HTTP objects
mock HTTP calls
Why?
calling external resources slows down our test
external resources might not be available when running tests

What are techniques for writing clean and maintainable tests?

tests are equally as important as source code
Many people don’t treat them that way!
spending time with messy test code
Soln?
write, clean maintainable testing code
common pattern (arrange, act, assert)
arrange
initialization code
act
triggering an action
assert
expectation code
What else?
beforeEach ( )
executes a function before each test
can initialize things before each test

How do we write clean, maintainable tests?
Hint: Arrange, Act, Assert
Arrange
setup the testing needs
Act
call function
Assert
make a statement about expected result

How do we see how much of our code is covered by tests?
Hint: ./node_modules/.bin/jest –coverage

Jest –coverage
as we write more tests, have better coverage
coverage report
can immediately see which parts of code are covered or not (by tests)

How can we make this test code cleaner?

Object structure (store) is cluttering testing code
will need this store object in other tests
repeating code is un-necessary
Soln?
create helper function for creating object structure (store object)
createState( )
makes test clean and readable

How do we write a test for testing the behavior of the resolveBug ( ) feature?

Totally okay to dispatch multiple actions
interacting with the system, looking at behavior
we are testing the behavior not the individual building blocks
Two Tests:
Happy Path
Negative Path

How can we test our loadBugs ( ) feature?
Hint: challenging and important excercise

most challenging and important excercises
Pay lots of attention
Lots of “aha” moments
Key Moment:
fakeAxios has two method signatures
call second signature to execute code before server responds
testing if using cache vs. server call
call method twice (dispatch loadBugs( ) x 2)
check to see if have single HTTP request to backend
fakeAxios.history returns an array of get requests (see docs)
can see if length of array equals 1

What are we going to learn about Redux and React integration?
How to subscribe to redux store to get data
What is the proper way to connect a React app to Redux?

using React Redux library
Mosh is going to show us the manual way
How do we connect our React app to Redux by scratch?

import configureStore module
pass store down using context (not prop drilling)
can provide at top of tree, all others have access
part of React course
How do we get the bugs from the backend and display them on the page?
Two Steps:
- subscribe to store
get list of bugs from store, render on screen
takes a function
executed everytime an action is dispatched
get bugs in store, store them locally in component
- dispatch(loadBugs())
to get bugs from backend and put them in the store

What is the problem with this code?

It’s very tedious
have to write code in every component
componentDidMount ( ) subscribe to store
componentWillUnmount ( ) unsubscribe from store
if forget anything, will cause memory leaks
very tedious and error prone
Soln?
React Redux
takes care of all this complexity
How do I use React-Redux library to connect my app to redux?
storeContext no longer needed
no longer do I have to maintain local state
React Redux will handle subscribing and unsubscribing from the store
don’t need componentWillUnmount
this.props

What is the connect ( ) function in React-Redux?
called a container component
why?
because it returns a function that can pass bugs component
so that bugs doesn’t know anything about store (redux)
Takes two arguments:
1. A function that takes state, returns part of the store our component is interested
state.entities.bugs.list
takes state and returns part interested in
pass as props to component
const mapStateToProps = state => ({
bugs: state.entites.bugs.list })
- mapDispatchToProps - dispatching actions
takes dispatch function from store
maps to props for component

What are hooks?
kind of a new thing (feature) in react
covered in detail in React course (final section)

Should I connect a top-level component or many small components to the Redux store?

If you connect a top-level component to the store, that component and all its children will get re-rendered every time the store gets updated.
Let’s say App component has two children: Bugs and Projects.
If you connect App component to the store, it gets notified every time the list of bugs or projects is modified. So if you add a bug, App component gets notified and the list of bugs as well as the list of projects will be re-rendered. This is unnecessary and can cause a performance penalty.
So, as a best practice, each component should independently subscribe to a small slice of the store it is interested in. This way it won’t be re-rendered if other slices of the store are updated.
