Mam nową bibliotekę :)

Piszę właśnie swoją nową bibliotekę. Częściowo jest to kolejna próba naprawienia Reduxa, jednak od poprzednich będzie się różnić tym, że zamiast tworzyć "alternatywę do Reduxa", to postanowiłem jednak napisać do tego Reduxa zwykły dodatek (middleware + automatyczne tworzenie reducera).

Biblioteka się nazywa Feedbacks (jak doczytacie dalej, to będzie jasne, skąd ta nazwa). I jest już dostępna na Githubie oraz na npm.

A więc Feedbacks zamienia Reduxa w reaktywny silnik stanu, która sam aktualizuje sobie stan na podstawie tego, co zwrócą:
- obserwable (celuję głównie w Rx.js, ale rozważam wsparcie dla innych, podobnych bibliotek)
- promisy
- reducery indywidualne dla każdego "pola" (właściwości) w stanie (trochę jak w combineReducers, ale lepiej, bo dodałem do tego bardziej zaawansowany pattern matching, np. można robić coś takiego:
match({type: 'foo', payload: {name: 'bar'}}, (value, action) => 42}
i dopasowywać akcję pod kątem tego, co ma w środku, a nie tylko pod kątem typu. No i te pola są reaktywne (reducer może zwrócić np. Observable, które będzie z automatu zamienione na przyszłe wartości danego pola).

Tym sposobem, dzięki reaktywności, rozwiąże się kwestia efektów ubocznych. Flow będzie taki:
- jest wysyłana akcja (normalnie, reduxowo, przez dispatch)
- akcja trafia na odpowiedni pattern, odpala się reducer dla danego pola.
- reducer ten dostaje wartość danego pola i akcję. Czyli taki tradycyjny podrzędny reducer (podrzędny, czyli nie główny). Jednak może on zwrócić "efekt" (efektem będzie np. Observable z Rx albo funkcja, która powinna zostać odpalona przez middleware. Funkcja ta może odpalić jakiś skutek uboczny i zwrócić np. Promise).

I teraz dopiero jest zabawa, ponieważ wartości ze skutków ubocznych (tj. wartości generowane przez Observable albo rezultat Promise'a) nie pójdą w kosmos, ale zostaną z powrotem wysłane do właściwości.

Jeśli brzmi to w zbyt skomplikowany sposób, to uwierzcie, że kod jest prosty. Pisze się po prostu takie jakby blueprinty:

const load = () => fetch('todos.json').then(response => response.json());
const blueprint = {
  time: Rx.interval(100),
  amount: init(0).
      .match('inc', v => v + 1)
      .match('inc', v => v - 1),
  todos: match('fetchTodos', () => load('todos.json'))
};
(to taki jakby "initial state", tylko, że właśnie to nie jest stan początkowy, tylko raczej przepis, szkic, plan tego co ma się dziać (stąd blueprint). Podejście deklaratywne FTW).

I potem na podstawie tego middleware i główny reducer podejmuje decyzje o tym, co ma robić. A reszta bez zmian, czyli Redux działa, React-Redux odświeża komponenty itp.

Anyway, teraz to oczywiście będę dalej rozwijał. Być może przepiszę implementację (dużo eksperymentowałem, więc kod nie jest jakiś super), może jeszcze jakaś lepsza dokumentacja i fajny landing page by się przydał, żeby jak ktoś z ulicy, kto wejdzie i poczyta o tym, żeby wiedział od razu o co chodzi i pomyślał, że to fajne, i można by tego użyć. I żeby wiedział, jak tego użyć itp.

Komentarze

Popularne posty z tego bloga

Dlaczego nie da się nadgonić frontendu

Absurdy Rekrutacji 2023

Przygody juniora (1)