From d4480bd67f9e7abc8668ea3c4d289180ef14a054 Mon Sep 17 00:00:00 2001 From: Yomesh Gupta Date: Fri, 26 Feb 2021 12:30:16 +0530 Subject: [PATCH] Added createStore --- customRedux/createStore.js | 96 ++++++++++++++++++++++++++++++++++++++ customRedux/index.js | 5 ++ index.js | 62 ++++++++++++++++++++++++ reducers/users.js | 22 +++++++++ reducers/videos.js | 22 +++++++++ 5 files changed, 207 insertions(+) create mode 100644 customRedux/createStore.js create mode 100644 customRedux/index.js create mode 100644 reducers/users.js create mode 100644 reducers/videos.js diff --git a/customRedux/createStore.js b/customRedux/createStore.js new file mode 100644 index 0000000..f6431e2 --- /dev/null +++ b/customRedux/createStore.js @@ -0,0 +1,96 @@ +const createStore = (reducer, preloadedState) => { + if (typeof reducer !== "function") { + throw new Error("Reducer must be a function"); + } + + let state = preloadedState; + let isDispatching = false; + const listeners = []; + + // returns the current state + const getState = () => { + if (isDispatching) { + throw new Error("Cannot call store.getState while dispatching"); + } + + return state; + }; + + // it is used to watch store changes. Listeners are invoked whenever an action is dispatched + const subscribe = (listener) => { + if (typeof listener !== "function") { + throw new Error("Store listeners should be of type function"); + } + + if (isDispatching) { + throw new Error("Cannot call store.subscribe while dispatching"); + } + + listeners.push(listener); + + return function unsubscribe() { + if (isDispatching) { + throw new Error("Cannot call store.unsubscribe while dispatching"); + } + + const index = listeners.indexOf(listener); + listeners.splice(index, 1); + }; + }; + + // it is used to trigger store changes, dispatch actions + const dispatch = (action) => { + if (typeof action !== "object") { + throw new Error("An action should be a plain object"); + } + + if (typeof action.type === "undefined") { + throw new Error("Action should have a type"); + } + + if (isDispatching) { + throw new Error("Cannot call store.dispatch while dispatching"); + } + + /** + * { type: 'ADD_VIDEO', payload: {...} } + * + * { + * videos: { data: [] } --> videos() + * users: { data: [] } --> users() + * } + * + * videos(state, { type: 'ADD_VIDEO', payload }) + * users(state, { type: 'ADD_VIDEO', payload }) + * + * (state, action) => { + * videos, + * users + * } + */ + + isDispatching = true; + + try { + state = reducer(state, action); + } finally { + isDispatching = false; + } + + listeners.forEach((listener) => listener()); + + return action; + }; + + dispatch({ + type: "INIT_ACTION", + }); + + return { + getState, + subscribe, + dispatch, + }; +}; + +module.exports = createStore; diff --git a/customRedux/index.js b/customRedux/index.js new file mode 100644 index 0000000..03bb29b --- /dev/null +++ b/customRedux/index.js @@ -0,0 +1,5 @@ +const createStore = require("./createStore"); + +module.exports = { + createStore, +}; diff --git a/index.js b/index.js index e69de29..5ef6c82 100644 --- a/index.js +++ b/index.js @@ -0,0 +1,62 @@ +const { combineReducers } = require("redux"); +const { createStore } = require("./customRedux/index"); +const videos = require("./reducers/videos"); +const users = require("./reducers/users"); + +const initialState = { + videos: { + data: [ + { + id: 1, + title: "Flat Array Interview Question", + link: "https://bit.ly/devtools-afiq", + }, + ], + }, +}; + +const rootReducer = combineReducers({ + videos, + users, +}); + +// createStore(reducer, preloadedState, enhancer) +const store = createStore(rootReducer, initialState); +/** + * { + * getState, + * subscribe, + * dispatch + * } + */ + +// to check the initial value of our store +console.log("------ INITIAL CALL ------\n", store.getState()); + +// to watch store changes +store.subscribe(() => { + console.log("Listener called"); +}); + +// to trigger store changes +store.dispatch({ + type: "ADD_VIDEO", + payload: { + id: 2, + title: "DOM API Interview Question", + link: "https://bit.ly/devtools-daiq", + }, +}); + +console.log("------ SECOND CALL ------\n", store.getState()); + +store.dispatch({ + type: "ADD_VIDEO", + payload: { + id: 3, + title: "Build Your Own Redux", + link: "https://bit.ly/devtools-byor", + }, +}); + +console.log("------ LAST CALL ------\n", store.getState()); diff --git a/reducers/users.js b/reducers/users.js new file mode 100644 index 0000000..2d60bf8 --- /dev/null +++ b/reducers/users.js @@ -0,0 +1,22 @@ +const USER_ACTIONS = { + ADD_USER: "ADD_USER", +}; + +function users( + state = { + data: [], + }, + action +) { + switch (action.type) { + case USER_ACTIONS.ADD_USER: + return { + ...state, + data: [...state.data, action.payload], + }; + default: + return state; + } +} + +module.exports = users; diff --git a/reducers/videos.js b/reducers/videos.js new file mode 100644 index 0000000..2272b41 --- /dev/null +++ b/reducers/videos.js @@ -0,0 +1,22 @@ +const VIDEOS_ACTIONS = { + ADD_VIDEO: "ADD_VIDEO", +}; + +function videos( + state = { + data: [], + }, + action +) { + switch (action.type) { + case VIDEOS_ACTIONS.ADD_VIDEO: + return { + ...state, + data: [...state.data, action.payload], + }; + default: + return state; + } +} + +module.exports = videos;