Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 23, 2020 06:55 pm GMT

Create Your Effector-like State Manager

Introduction

We have a lot of state managers in our Javascript-World and use them every day, but now it's a time to understand "How they work".

There's a very nice state manager Effector.js which is very simple to use in your application, also it's easy to replace your current global state manager. So, I recommend to use it for your project and doesn't matter for which framework. I use it on my React Apps.

Let's start to create own Effector-like state manager!

We're gonna create basics looks like Effector, of course Effector is deeper and complex and our state manager is just simple version of it.

  1. Firstly, let's create a js file (effector-clone.js) with our state manager. We start with createStore function that create our store instance with events.
export const createStore = initState => {  let state = initState; // State of instance    let events = new Map(); // Events subscribed to the current store    let watchers = []; // Array of watcher that get called on the state changes  let store = {    getState: () => state, // Get current state of the store        on(event, cb) {}, // Method to subscribe event        dispatch(event, payload) {}, // Dispatch event to make changes in the store        watch(cb) {} // Subscribe to the state changes  };  return store;};
Enter fullscreen mode Exit fullscreen mode
  1. We need to add a function that creates event instance.

Let's add this code into the file above!

export const createEvent = () => {    // Return function that iterates stores linked to the event  let event = payload => {    event.stores.forEach((store) => {      store.dispatch(event, payload);    });  };    // Let's link stores to the event    // We're gonna call stores' dispatches on event's call  event.stores = [];  return event;};
Enter fullscreen mode Exit fullscreen mode
  1. Implement on, dispatch and watch methods for the store instance.
export const createStore = initState => {  let state = initState;    let events = new Map();    let watchers = [];  let store = {    getState: () => state,        on(event, cb) {            // Subscribe to store            // We use event instance as key for map and callback as a value            // [event: Function]: callback: Function            // Set event in the events map if it hasn't the event in this store            if (!events.has(event)) {        events.set(event, cb);                event.stores.push(this);      }      return this;        },        dispatch(event, payload) {            // We get and call event's callback and            // set it's result to the store's state            const cb = events.get(event);      if (cb && typeof cb === "function") {        let newState = cb(state, payload);                // Check if state is the same        if (newState !== state) {          state = newState;        }      }            // Iterable callbacks on the state changes            watchers.forEach((watch) => watch(state, payload));        },        watch(cb) {      watchers.push(cb);            // Return function to unsubscribe the watcher      return () => {        watchers = watchers.filter((i) => i !== cb);      };    }  };  return store;};
Enter fullscreen mode Exit fullscreen mode

Core part of our state manager is Done!

Use it with React + hooks

We're gonna use it as a global state manager. It's also okay to use inside your component.

  1. Create useStore.js file and add this simple code.
import { useEffect, useState } from "react";export const useStore = store => {    // We get initial state of the store  const [state, setState] = useState(store.getState());  useEffect(() => {        // Pass setState function as a callback        // store.watch() returns unsubscribe function    const unsubscribe = store.watch(setState);    return () => {            // Unsubscribe our watcher on component unmount      unsubscribe();    };  }, [store]);  return state;};
Enter fullscreen mode Exit fullscreen mode
  1. Create counterStore.js file with our counter store
import { createStore, createEvent } from "./effector-clone";export const $counter = createStore(0);export const inc = createEvent();export const dec = createEvent();export const reset = createEvent();$counter  .on(inc, (state) => state + 1)  .on(dec, (state) => state - 1)  .on(reset, () => 0);
Enter fullscreen mode Exit fullscreen mode
  1. Create a Counter.jsx component
import React from "react";import { $counter, inc, dec, reset } from "./counterStore";import { useStore } from "./useStore";export const Counter = () => {  const total = useStore($counter);  return (    <>      <p>Total: <b>{total}</b></p>      <button onClick={dec}>-</button>      <button onClick={reset}>Reset</button>      <button onClick={inc}>+</button>    </>  );};
Enter fullscreen mode Exit fullscreen mode

Magic works

Conclusion

We created own custom state manager and its size with useStore hook is only 1.4kb. I hope now it's a bit cleaner about how it works and how to create own state manager. Of course it needs upgrades and error handlers, but depends on your feedbacks I'll publish an article about these upgrades.

Try it on codesandbox!

Thank You For Reading!


by Orkhan Jafarov


Original Link: https://dev.to/gigantz/create-your-effector-like-state-manager-1nfd

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To