Process involving using Redux with React
Redux Store
- Redux store is a single source of truth
- Redux store is read-only
- Redux store is immutable
- Redux store is updated by pure functions
- Redux store is updated by actions
- Redux store is updated by reducers
- Redux store is updated by dispatching actions
- Redux store is updated by middleware
- Redux store is updated by async actions
- Redux store is updated by thunks
- Redux store is updated by sagas
Middleware
Calling APIs
Testing Redux apps
Integration With React
Key to understanding Redux is to understand the following concepts:
- Store
- Functional programming
- Procedural
- Object oriented
- Event-driven
Process
- concept behind redux
- functional programming
- Function composition
- Lodash
- Currying
- Pure function
Function composition:
const compose = (f, g) => (data) => f(g(data));
// or
let input = " JavaScript ";
let output = trim(toLowerCase(input));
Lodash:
import { compose, pipe } from "lodash/fp";
let input = " JavaScript ";
// order of execution is from right to left
let output = compose(trim, toLowerCase)(input);
// or
// order of execution is from left to right
let output = pipe(toLowerCase, trim)(input);
Currying:
Normal method for adding two numbers
const add = (a, b) => a + b;
add(2, 3); // 5
Currying method for adding two numbers
const add = (a) => (b) => a + b;
add(2)(3); // 5
// or
function add(a) {
return function (b) {
return a + b;
};
}
add(2)(3); // 5
Example of currying
const trim = (str) => str.trim();
const toLowerCase = (str) => str.toLowerCase();
const wrap = (type) => (str) => `<${type}>${str}</${type}>`;
const result = pipe(trim, toLowerCase, wrap("div")); // <div>javascript</div>
Pure function
// imPure function
function add(a) {
return a + Math.random();
}
add(2); // 2.43242342
// Pure function
function add(a, b) {
return a + b;
}
add(2, 3); // 5
Hence, Pure function is a function that returns the same output for the same input. Pure function cannot have side effects. Pure function is predictable. Pure function is testable. Pure function is easy to debug. Pure function cannot mutate the input. pure function cannot mutate the external variable. Pure function cannot have random values, date, time, etc. Pure function cannot have console.log, alert, etc. Pure function cannot have async code, fetch, etc. Pure function cannot have DOM manipulation, document.getElementById, etc. Pure function cannot have network calls, fetch, etc. Pure function cannot have database calls, SQL, etc. Pure function cannot have file system calls, fs, etc. Pure function cannot have global variables, window, etc. Pure function cannot have local storage, session storage, etc. Pure function cannot have cookies, cache, etc. Pure function cannot have browser storage, web storage, etc. Pure function cannot have the navigator object, location object, etc. Pure function cannot have the history object, screen object, etc. Pure function cannot have the console object, alert object, etc. Pure function cannot have the confirm object, prompt object, etc. Pure function cannot have the fetch object, XMLHttpRequest object, etc. Pure function cannot have the WebSocket object, etc.
Advantage of Pure function :
- Self-documenting (since it returns the same output for the same input, also doesn't use any parent scope variables)
- Easy to test (since it returns the same output for the same input)
- Easy to debug(we can easily find the bug)
- Concurrency (since its independent of external variables, it can be run in parallel)
- Cacheable (since output gonna be same for same input, we can store it in cache and re use that output, saving execution time)
Advantage of Immutable data:
- Predictable
- Faster Change Detection
- Concurrency
- Cacheable
- Easy to test
- Easy to debug
- Self-documenting
- Easy to maintain
- Easy to refactor
Disadvantage of Immutable data:
- Memory consumption
- Performance
- Complexity
Editing properties of Object
const person = { name: "John", age: 25 };
const updated = Object.assign({}, person, { age: 26, name: "John Doe" });
// or
const updated = { ...person, age: 26, name: "John Doe" };
// above code is not proper way to update object, if object is nested with another object then it will not work : cuz it performs shallow copy
// Example for shallow copy
const person = {
name: "John",
age: 25,
address: {
city: "New York",
country: "USA",
},
};
const updated = { ...person, age: 26 };
updated.address.city = "New Delhi";
console.log(person.address.city); // New Delhi
// Deep copy
const updated = {
...person,
address: {
...person.address,
city: "New Delhi",
},
};
console.log(person.address.city); // New York
Editing properties of Array
const numbers = [1, 2, 3];
// Adding
const added = [...numbers, 4];
// adding element in specific index
const index = numbers.indexOf(2);
const added = [...numbers.slice(0, index), 4, ...numbers.slice(index)];
// added = [1, 4, 2, 3]
Using Immutable.js:
import { Map } from "immutable";
let book = Map({ title: "Harry Potter" });
console.log(book.get("title")); // Harry Potter
console.log(book.toJS()); // { title: "Harry Potter" }
function publish(book) { // this this is mutating the book object
return book.set("isPublished", true);
}
book = publish(book); // this is not mutating the book object instead it is returning new object with isPublished property set to true
Using immer.js:
import produce from "immer";
let book = { title: "Harry Potter" };
const publish = (book) => {
return produce(book, (draftBook) => {
draftBook.isPublished = true;
});
};
let updated = publish(book);
Redux Architecture
- Redux store
- Actions
- Reducers
where,
Store: Single source of truth, accessible by all components/ all parts of the application/UI
- We cannot directly update the store (store is read-only)
- We can update the store by dispatching actions
- We can update the store by reducers
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
case "DECREMENT":
return { count: state.count - 1 };
default:
return state;
}
}
// or
function reducer(state, action) {
const updated = { ...state };
if (action.type === "INCREMENT") {
updated.count++;
}
}
Actions: (Event) Plain JavaScript object Reducers:(Event Handler) Pure functions
Action[Event] -(dispatch)->
Store -(forward action) ->
<-(updated state) Reducer[Event Handler]
Steps to build redux
- Design the store
- define the action
- create a reducer
- setup the store