Skip to content

DevOpsPlayground/Redux-DELETE

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Introduction to State Management Using Redux

In this guide, we will walk through the steps to set up a global state management library.

Before you start

npm i
npm run build:css

Step 1 - Function to create store:

store.ts

export const createStore = (reducer: Reducer, initialState: StoreState) => {
  const store: Store = {
    state: initialState,
    listeners: [],
    dispatch: () => {},
    subscribe: () => {},
    getState: () => store.state,
  };

  store.subscribe = (listener) => {
    store.listeners.push(listener);
  };

  store.dispatch = (action) => {
    console.log("> Action", action);
    store.state = reducer(store.state, action);
    store.listeners.forEach((listener) => listener());
  };

  return store;
};

type.ts

export type Store = {
  state: StoreState;
  listeners: (() => void)[];
  getState: () => StoreState;
  subscribe: (listener: () => void) => void;
  dispatch: (action: Action) => void;
};

Step 2 - Create the initial state:

store.ts

export const getInitialState = () => ({
  // This would be a redux thunk action that calls our API
  bookList: books,
  booksInBasket: [],
});

types.ts

export type Book = {
  title: string;
  author: string;
  quantity: number;
};

export type StoreState = {
  bookList: Book[];
  booksInBasket: Book[];
};

Step 3 - Create action:

store.ts

export const addBookToBasketAction = (
  title: string,
  author: string,
  quantity: number
): Action => ({
  type: "book/addBookToBasket",
  payload: { title, author, quantity },
});

types.ts

export type Action = {
  type: string;
  payload: Book;
};

Step 4 - Create reducer:

store.ts

export const reducer: Reducer = (prevState, action) => {
  switch (action.type) {
    case "book/addBookToBasket": {
      return prevState;
    }
    default: {
      return prevState;
    }
  }
};

types.ts

export type Reducer = (state: StoreState, action: Action) => StoreState;

Step 5 - Create the store:

index.ts

export const store = createStore(reducer, getInitialState());

Step 6 - render initial state and add to subscriber:

components.ts

export const renderSupplierStoreList = (bookList: Book[]) =>
  renderHTMLElement(bookList, "supplierStore", "add", "book/addBookToBasket");

index.ts

renderSupplierStoreList(store.getState().bookList);

store.subscribe(() => {
  const state = store.getState();
  console.log("> State changed:", state);
  renderSupplierStoreList(state.bookList);
});

— Build and run application —

npm run build
npm run start

Step 7 - fill in reducer functionality:

store.ts

const findBook = (arr: Book[]) =>
  arr.find(
    (book) =>
      book.author === action.payload.author &&
      book.title === action.payload.title
  );
switch (action.type) {
  case "book/addBookToBasket": {
    if (action.payload.author && action.payload.title) {
      // updates supplier list
      const bookInList = findBook(prevState.bookList);
      if (bookInList && bookInList.quantity > 0) {
        const updatedBookList = prevState.bookList.map((book) => {
          if (
            book.author === action.payload.author &&
            book.title === action.payload.title
          ) {
            return {
              ...book,
              quantity: book.quantity - 1,
            };
          }
          return book;
        });

        // updates customer basket
        const bookInBasket = findBook(prevState.booksInBasket);
        let updatedBooksInBasket = [...prevState.booksInBasket];
        if (!bookInBasket) {
          updatedBooksInBasket.push({ ...bookInList, quantity: 1 });
        } else {
          updatedBooksInBasket = updatedBooksInBasket.map((book) => {
            if (
              book.author === action.payload.author &&
              book.title === action.payload.title
            ) {
              return {
                ...book,
                quantity: book.quantity + 1,
              };
            }
            return book;
          });
        }

        return {
          ...prevState,
          bookList: updatedBookList,
          booksInBasket: updatedBooksInBasket,
        };
      }
      console.error("Book list has quantity of 0");
      return prevState;
    }
    console.error("Need title and author to manipulate state");
    return prevState;
  }
}

— build —

npm run build

Step 8 - Add components to listen to booksInBasket:

components.ts

export const renderCustomerBasket = (booksInBasket: Book[]) =>
  renderHTMLElement(
    booksInBasket,
    "customerBasket",
    "remove",
    "book/removeBookFromBasket"
  );

export const renderCustomerDashboard = (booksInBasket: Book[]) =>
  renderHTMLElement(
    booksInBasket,
    "customerDashboard",
    "remove",
    "book/removeBookFromBasket"
  );

index.ts

renderCustomerBasket(state.booksInBasket);
renderCustomerDashboard(state.booksInBasket);

— build —

Step 9 - add remove book reducer:

store.ts

case "book/removeBookFromBasket": {
if (action.payload.author && action.payload.title) {
// updates customer basket
const bookInBasket = findBook(prevState.booksInBasket);

        if (!bookInBasket) {
          console.error("Book not found in basket");
          return prevState;
        }

        let updatedBooksInBasket = [...prevState.booksInBasket];
        if (bookInBasket.quantity === 1) {
          updatedBooksInBasket = updatedBooksInBasket.filter(
            (book) =>
              book.author !== action.payload.author ||
              book.title !== action.payload.title
          );
        } else {
          updatedBooksInBasket = updatedBooksInBasket.map((book) => {
            if (
              book.author === action.payload.author &&
              book.title === action.payload.title
            ) {
              return {
                ...book,
                quantity: book.quantity - 1,
              };
            }
            return book;
          });
        }

        // updates supplier list
        const updatedBookList = prevState.bookList.map((book) => {
          if (
            book.author === action.payload.author &&
            book.title === action.payload.title
          ) {
            return {
              ...book,
              quantity: book.quantity + 1,
            };
          }
          return book;
        });

        return {
          ...prevState,
          bookList: updatedBookList,
          booksInBasket: updatedBooksInBasket,
        };
      }
      console.error("Need author and title to identify book");
      return prevState;
    }

— build —

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 86.0%
  • HTML 12.2%
  • Other 1.8%