Pure Functions

function add(a, b) {
    return a + b;
}

function capitalize(str) {
    return str.slice(0, 1)
        .toUpperCase()
        .concat(str.slice(1));
}

/*
    built-in pure functions:
        filter, map, reduce, some, every, slice, concat
*/

Pure functions

let result = null;

function add(a, b) {
    result = a + b;
    return result;
}

function request(url) {
    return fetch(url);
}

function setName(obj, name) {
    obj.name = name;

    return obj;
}

/*
    built-in impure functions:
        sort, reverse, push, splice, shift, unshift
*/

Impure functions

Immutability

const obj = { name: 'John' };

const a = obj;
const b = obj;

b.name = 'James';

console.log(b.name) // 'James'
console.log(obj.name) // 'James'
console.log(a.name) // 'James'

Javascript has mutable objects by default

let obj = { name: 'John', age: 20 };

const b = obj;

obj = { ...obj, name: 'James' };

console.log(obj) // { name: 'James', age: 20 }
console.log(b) // { name: 'John', age: 20 }
const state = {
    users: [
        { name: 'admin', isAdmin: true },
    ],
    movies: [],
};

getUsers()
    .then((users) => state.users.push(...users))
    .catch(err => console.log(err));

function removeMovie(movieId) {
    const index = state.movies.findIndex(movie => movie.id === movieId);
    state.movies.splice(index, 1);
}

function removeAdmin(userName) {
    const user = state.users.find(user => user.name === userName);
    user.isAdmin = false;
}

Mutable style

class Store {
    constructor(state) {
        this.state = state;
    }

    getState() {
        return this.state;
    }

    setState(newState) {
        this.state = newState;
    }
}

const store = new State({
    users: [
        { name: 'admin', isAdmin: true },
    ],
    movies: [],
});

getUsers()
    .then((users) => {
        const newState = {
            ...store.getState(),
            users,
        }

        store.setState(newState);
    })
    .catch(err => console.log(err));


Immutable style

function removeMovie(movieId) {
    const state = store.getState();
    const newState = {
        ...state,
        movies: state.movies.filter(
            movie => movie.id !== movieId
        )
    };

    state.setState(newState);
}

function removeAdmin(userName) {
    const state = store.getState();
    const newState = {
        ...state,
        users: state.users.map(user => {
            if (user.name === userName) {
                return { ...user, { isAdmin: false } };
            }

            return user;
        })
    }

    store.setState(newState);
}

Flux is a pattern for managing data flow in your application. The most important concept is that data flows in one direction.

Flux parts:

  • Dispatcher

  • Store

  • Action

  • View

Redux is a predictable state container for JavaScript apps.

Redux main principles

 

  • Read-only state

The only way to change the state is to emit an action, an object describing what happened.

  • Changes are made with pure functions

To specify how the state tree is transformed by actions, you write pure reducers.

  • Single source of truth

The state of your whole application is stored in an object tree within a single store.

Reducer changes state based on dispatched action and current state

reduce((currentState, action) => {
    // logic
}, initialState);
npm install redux
import { createStore } from 'redux';

const reducer = (state = 0, action) => {
    if (action.type === 'INCREMENT') {
        return state + 1;
    } else if (action.type === 'DECREMENT') {
        return state - 1;
    }
    return state;
};

const store = createStore(reducer);

// actions
const inc = { type: 'INCREMENT' };
const dec = { type: 'DECREMENT' };

store.dispatch(inc);
store.dispatch(inc);
store.dispatch(inc);
store.dispatch(dec);

store.getState(); // outputs 2
const ubsubscribe = store.subscribe(() => {
    const currentState = store.getState();
    console.log(currentState);
});


store.dispatch(inc);
store.dispatch(inc);
store.dispatch(inc);

unsubscribe();

store.dispatch(inc);
store.dispatch(inc);
store.dispatch(inc);

Middlewares

Middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.

import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';


const reducer = (state = 0, action) => {
    if (action.type === 'INCREMENT') {
        return state + 1;
    } else if (action.type === 'DECREMENT') {
        return state - 1;
    }
    return state;
};

const store = createStore(reducer, applyMiddleware(logger));

store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' })
const mymiddleware = store => next => action => {
    console.log('My middleware in action!');
    return next(action);
}
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';


const reducer = (state = 0, action) => {
    if (action.type === 'INCREMENT') {
        return state + 1;
    } else if (action.type === 'DECREMENT') {
        return state - 1;
    }
    return state;
};

const mymiddleware = store => next => action => {
    console.log('My middleware in action!');
    return next(action);
}

const store = createStore(reducer, applyMiddleware(mymiddleware, logger));

store.dispatch({ type: 'INCREMENT' });
store.dispatch({ type: 'DECREMENT' });

References

redux lecture

By Nikita Rudy

redux lecture

  • 527