Skip to content

Instantly share code, notes, and snippets.

@AndreiCalazans
Created June 30, 2020 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndreiCalazans/b686afb6ac74b7f434b2ffa4cd93e931 to your computer and use it in GitHub Desktop.
Save AndreiCalazans/b686afb6ac74b7f434b2ffa4cd93e931 to your computer and use it in GitHub Desktop.
function makeRoute(route, params) {
return {
route,
params,
};
}
class StateManager {
constructor(initialState) {
let subscriptions = [];
let state = initialState;
this.getState = () => state;
this.setState = (newState) => {
state = newState;
if (subscriptions.length) {
subscriptions.forEach((fn) => fn(state));
}
};
this.subscribe = (onChangeCallback) => {
console.warn(
"when subscribing use named functions to unsubscribe correctly"
);
subscriptions.push(onChangeCallback);
};
this.unsubscribe = (onChangeCallback) => {
subscriptions = subscriptions.filter((fn) => {
return fn !== onChangeCallback;
});
};
}
}
class Navigation extends StateManager {
constructor(initialState) {
super(initialState);
}
replaceRoute(route, params) {
const replaceLastRouteMapper = (historyRoute, index) => {
if (historyRoute.route == this.getState().currentRoute) {
return {
route,
params,
};
}
return historyRoute;
};
this.setState({
currentRoute: route,
history: this.getState().history.map(replaceLastRouteMapper),
});
}
pushRoute(route, params) {
this.setState({
currentRoute: route,
history: [...this.getState().history, makeRoute(route, params)],
});
}
popRoute() {
if (this.getState().history.length === 1) {
throw "Navigation error - popRoute was called on stack with a single route";
}
const newHistory = this.getState().history.slice(
0,
this.getState().history.length - 1
);
this.setState({
currentRoute: newHistory[newHistory.length - 1].route,
history: newHistory,
});
}
}
const NavigationModule = new Navigation({
currentRoute: "Lander",
history: [makeRoute("Lander", {})],
});
console.log(NavigationModule);
NavigationModule.subscribe((e) => console.log("updated", e));
NavigationModule.pushRoute("Detail", { id: 12 });
NavigationModule.replaceRoute("Two", { id: 44 });
NavigationModule.pushRoute("Video", { id: 99 });
NavigationModule.unsubscribe((e) => console.log("updated", e));
NavigationModule.pushRoute("Detail", { id: 12 });
@AndreiCalazans
Copy link
Author

Initial TypeScript annotation:

type Subscription<AnyState> = (state: AnyState) => void;

export class StateManager<StateType> {
  getState: () => StateType;
  setState: (state: StateType) => void;
  subscribe: (state: Subscription<StateType>) => void;
  unsubscribe: (state: Subscription<StateType>) => void;


  constructor(initialState: StateType) {
    let subscriptions: Array<Subscription<StateType>> = [];
    let state = initialState;
    this.getState = () => state;
    this.setState = (newState) => {
      state = newState;
      if (subscriptions.length) {
        subscriptions.forEach((fn) => fn(state));
      }
    };

    this.subscribe = (onChangeCallback) => {
      console.warn(
        "when subscribing use named functions to unsubscribe correctly"
      );
      subscriptions.push(onChangeCallback);
    };

    this.unsubscribe = (onChangeCallback) => {
      subscriptions = subscriptions.filter((fn) => {
        return fn !== onChangeCallback;
      });
    };
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment