Skip to content

Instantly share code, notes, and snippets.

@artalar
Last active October 24, 2018 07:45
Show Gist options
  • Select an option

  • Save artalar/7edfcacc84cd6fe0ab43e883564e4dbc to your computer and use it in GitHub Desktop.

Select an option

Save artalar/7edfcacc84cd6fe0ab43e883564e4dbc to your computer and use it in GitHub Desktop.
pathon v2 RFC
// workflow.js
import {
createReactCreator,
child,
// updateQueue is list of updates priority
// `updateQueue` from `immutablePreset` have `compute` property
// you must use it if you want change react own state before other reactions
updateQueue
} from "pathon/immutablePreset";
// the react - is function.
// If you calls it trigger `1` part subscribers queue and further
const createReact = createReactCreator(updateQueue);
const loadStates = {
init: "initial",
req: "request",
get: "load",
err: "error"
};
const data = createReact({ list: [{ value: null }] });
const list = child(data, "list");
const firstListItem = child(data, "0");
const load = createReact([loadStates.init]);
// type Target = React
// type PatternMatch = number(===) | string(===) | null(===) | (Object | array)(shallowEqual()) | Function (predicate)
// type Callback = Function
// `.when` accept (Target, Callback) or (Target, PatternMatch, Callback)
data
.when(load, [loadStates.get], ([, list]) => data({ list }))
.when(load, [loadStates.err], () => data({ list: [] }));
load
// you can move this boilerplate to the function if needed
.when(load.compute, undefined, () => load([loadStates.req]))
.when(load, [loadStates.req], async () => {
try {
load([loadStates.get, await fetch()]);
} catch (error) {
load([loadStates.err, error]);
}
});
// Component.js
load();
import { reactQueueTracker } from "pathon";
function immutableMerge(prevState, newValue) {
/**/
}
function isNotEqual(newState, prevState) {
return newState !== prevState;
}
export function createReactCreator(updateQueue) {
const newCreateReact = reactQueueTracker(updateQueue);
return initialState => {
const newReact = newCreateReact(initialState);
newReact.when(
// subscribe to any update
newReact.format,
// miss unnecessary updates
isNotEqual,
// formatting new value to state type format
// for example lets imagine us preset is works like React.Component.setState and immutable
// so if `newValue` is `{ v2: true }` and `prevState` is `{ v1: true }`
// then we must to receive new link to `{ v1: true, v2: true }` value
// furthermore preset may work with Set, Map and any other data types
// you can manually change or write your own presets
(newValue, prevState) => newReact(immutableMerge(prevState, newValue)) // TODO: `newReact.child` for avoidance unnecessary predicate calls ?
);
return newReact;
};
}
export function child(parentReact, key) {
const initialState = parentReact.get()[key];
// `createReact` from another react saves queue execution sequence
const react = parentReact.createReact(initialState);
const predicate = (newParentState, prevParentState) => {
let newState;
try {
newState = newParentState[key];
} catch (error) {
parentReact.off(callback);
return false;
}
return newState !== prevParentState[key];
};
const callback = newState => {
react(newState[key]);
};
parentReact.when(
// type Target = React
// type PatternMatch = number(===) | string(===) | null(===) | (Object | array)(shallowEqual()) | Function (predicate)
// type Callback = Function
// (Target, Callback) | (Target, PatternMatch, Callback)
parentReact.child,
// subscribe only to changed value
predicate,
// current "child" react will update all it self children
// wait when parent react update it self other children
// then parent react update it self parent subscribers
// then parent react update it self compute subscribers
// then current react update it self compute subscribers
// then parent react update it self subscribers
// then current react update it self subscribers
callback
);
// subscribe parent to child updates
react.when(react.parent, isNotEqual, parentReact);
return react;
}
// react updates
// calls every parts of queue subscribers
// start by `1`
// after that calls the [just] react subscribers (like `4` part of queue)
export const updateQueue = {
format: 0,
child: 1,
parent: 2,
compute: 3
};
@artalar

artalar commented Oct 20, 2018

Copy link
Copy Markdown
Author

RFC по pathon 2.0 готово:
Что внутри:

  • минималистичный API: евент и стор - все одно и тоже - просто набор тригеров на изменение состояния
  • мощнейшие возможности для функциональной композиции (собственно это и описано в 2-immutablePreset.js)
  • фундаментальное исправление проблемы состояния гонки, ромбовидных зависимостей и т.п.: API заставляет пользователя (updateQueue) самому думать об этом, при этом не нагружая его мозг (react.compute и все). Т.е. в примере есть два типа подписок: простые при отсутствии необходимости мгновенной реакции (для сайд-эффектов и перерендера компонентов отображения) и compute для вычисления значений необходимых слою данных приложения. Я еще исправлю пример на более реалистичный и наглядный.
  • вес кода библиотеки не должен привышать 10KB не минифицированный!
  • при этом остаются безграничные возможности для расширения. Например, как видно из 2-immutablePreset.js на основе updateQueue.parent можно создавать даже рекурсивные структуры данных. Все чем занимается pathon - вызов очереди очередей подписок.
  • должен быть простой интероп со стримами
  • динамические модули делать элементарно, связывая новый кусок стора и рут через updateQueue.parent

Самое главное что с updateQueue и .when получилось круто инкапсулировать и разбить логику работы самой библиотеки. Это видно по тому что child как модуль пишется очень просто и не имеет никакой связанности с ядром (reactQueueTracker).

Для pathon v2 писать какие-то хелперы будет сложнее, чем мидлвары для редакса, зато функциональности в разы больше.

@artalar

artalar commented Oct 22, 2018

Copy link
Copy Markdown
Author

DI?

@artalar

artalar commented Oct 24, 2018

Copy link
Copy Markdown
Author

targets:

  • small weight
  • DI
  • easy abstraction
  • small api
  • flexible and extensible
  • glitch free
  • observable friendly
  • recursive friendly

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