Skip to content

Instantly share code, notes, and snippets.

@artalar
Last active May 28, 2018 03:06
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 artalar/7184057ddc9209c5caf094054e125489 to your computer and use it in GitHub Desktop.
Save artalar/7184057ddc9209c5caf094054e125489 to your computer and use it in GitHub Desktop.
import { createRootPath, immutablePreset } from 'pathon';
const createLogger = id => (...args) => console.log(`ID: ${id}`, ...args);
const pathSome = createRootPath(
// initial state
{ list: [{ id: 0, value: Math.random() }] },
// default setters and getters (for `path` to)
immutablePreset
);
const pathSomeList = pathSome.path('list');
// special method for track only structure of collection
// accept new `get` handler by first argument
// trigger only on `pathSomeList.set()`
// (will not trigger for `pathSomeList.path(key).set()`)
const pathSomeListIds = pathSomeList.shape(state => state.map(({ id }) => id));
// special method for track and memorize computed data
// trigger on `pathSomeList.set()` and `pathSomeList.path(key).set()`
const pathSomeListSum = pathSomeList.map(
state => state.reduce((acc, { value }) => acc + value), // computed
(prevCalc, newCalc) => prevCalc === newCalc // comparator
);
// it effective to watch list and every item separately
const pathSomeListItem0 = pathSomeList.path('0');
pathSome.watch(createLogger('pathSome'));
pathSomeList.watch(createLogger('pathSomeList'));
pathSomeListIds.watch(createLogger('pathSomeListIds'));
pathSomeListSum.watch(createLogger('pathSomeListSum'));
pathSomeListItem0.watch(createLogger('pathSomeListItem0'));
// update store === dynamic expansion
// after this you can `pathSome.path('newField').watch(callback)`
pathSome.set({ newField: true });
// "ID: pathSome ...."
pathSomeListItem0.set({ value: Math.random() });
// "ID: pathSome ...."
// "ID: pathSomeList ...."
// "ID: pathSomeListSum ...."
// "ID: pathSomeListItem0 ...."
// watchers for `pathSomeListIds` will not trigger
// `.set` - is method for "extend" collection, but not modify old elements
// so it doesn't trigger watchers in nested elements
pathSomeList.set([...pathSomeList.get(), { id: 1, value: Math.random() }]);
// "ID: pathSome ...."
// "ID: pathSomeList ...."
// "ID: pathSomeListIds ...."
// "ID: pathSomeListSum ...."
// `.reset` - is method for rewrite collection
// so it will trigger watchers in nested elements
pathSomeList.reset(pathSomeList.get().map(element => ({ ...element, newValue: true })));
// "ID: pathSome ...."
// "ID: pathSomeList ...."
// "ID: pathSomeListIds ...."
// "ID: pathSomeListSum ...."
// "ID: pathSomeListItem0 ...." // <-- your attention
// TODO: `compose`
@artalar
Copy link
Author

artalar commented May 28, 2018

(речь о новом state manager)
Преимущества библиотеки:
(path - это своеобразная автогенерирующаяся линза)

  1. Трекается (вызывается колбек подписчика) только то что нужно(!!!).
  2. Возможность работы с любым типом данных (второй аргумент у createRootPath и .path принимает конфиг в котором определяются хендлеры по умолчанию для нового и всех вложенных [.path] изменений и запросов ). Мутабельные структуры так же можно использовать - потому что отслеживание идет по подписке на path
  3. Динамическое расширение стора
  4. Крайне минимальное апи ("расширенное" апи, описание пресета для хедлинга, будет доступно по умолчанию для самых популярных типов структур). .path, .shape, .map, .set, .reset, .watch, .unwatch.
  5. Малый вес библиотеки

@artalar
Copy link
Author

artalar commented May 28, 2018

export const immutablePreset = {
  set: (state, payload) => {
    if (state instanceof Map) {
      return new Map([...state, ...payload]);
    } else if (state instanceof Set) {
      return new Set([...state, ...payload]);
    } else if (Array.isArray(state)) {
      return payload; // ?
    } else {
      return { ...state, ...payload };
    }
  },
  setPath: path => (state, payload) => {
    if (state instanceof Map) {
      return new Map(state).set(path, payload);
    } else if (state instanceof Set) {
      const newState = [...state];
      newState[path] = payload;
      return new Set(newState);
    } else if (Array.isArray(state)) {
      const newState = state.slice();
      newState[path] = payload;
      return newState;
    } else {
      return { ...state, [path]: payload };
    }
  },
  get: state => state,
  getPath: path => state => {
    if (state instanceof Map) {
      return state.get(path);
    } else if (state instanceof Set) {
      return [...state][path];
    } else {
      return state[path];
    }
  },
  // optional memorization
  comparator: (prevValue, newValue) => prevValue === newValue
};

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