Maciej Stasiełuk, 29.09.20
Action
Dispacher
View
Stores
Manages data flow in a unidirectional flow
Complicated, hard to maintain store models
Action
Reducers
View
Store
dispatch({ type: SOME_ACTION, payload: id });
function reducer(state = {}, action) {
switch (action.type) {
case SOME_ACTION:
// sync business logic here
const updatedState = {};
return {...state, ...updatedState};
default:
return state;
}
}
Better, simpler architecture
Business logic must be synchronous
Action
Reducers
View
Store
const doSomething = (dispatch, id) => {
dispatch({ type: SOME_ACTION, payload: id });
fetch(/**/).then(data => {
dispatch({ type: SOME_ACTION_SUCCESS, payload: data });
}).catch(err => {
dispatch({ type: SOME_ACTION_FAILED, payload: err });
});
};
Can perform async logic
No easy access
to the store
Action
Reducers
View
Store
const doSomething = id => (dispatch, getState) => {
const state = getState();
dispatch({ type: SOME_ACTION, payload: id });
fetch().then(data => {
dispatch({ type: SOME_ACTION_SUCCESS, payload: data });
}).catch(err => {
dispatch({ type: SOME_ACTION_FAILED, payload: err });
});
};
Simple and have
access to state
Cannot cancel or limit actions, hard to manage complicated logic
Middleware
Action
Reducers
View
Store
const doSomething = id => ({ type: SOME_ACTION, payload: id });
function* watchDoSomething() {
while ( yield take(SOME_ACTION) ) {
const doSomethingTask = yield(fork(doSomething));
yield take (SOME_ACTION_CANCEL);
yield cancel(doSomethingTask);
}
}
function* doSomething(action) {
try {
const data = yield fetch(/**/);
yield put({ type: SOME_ACTION_SUCCESS, payload: data });
}
catch(err) {
yield put({ type: SOME_ACTION_FAILED, payload: err });
}
finally {
if (yield cancelled()) {
yield put({ type: SOME_ACTION_CANCELLED });
}
}
}
Support cancellation and limiting, so can manage complicated cases
Lots of boilerplate and generator syntax is hard to read for most people
Sagas
Action
Reducers
View
Store
const doSomething = id => ({ type: SOME_ACTION, payload: id });
const soSomethingEpic = action$ =>
action$
.ofType(SOME_ACTION)
.mergeMap(action =>
ajax.get(/**/)
.map(data => ({ type: SOME_ACTION_SUCCESS, payload: data }))
.catch(err => ({ type: SOME_ACTION_FAILED, payload: err }))
.takeUntil(action$.ofType(SOME_ACTION_CANCELLED))
);
Can use full power of Observables and RxJS
Still some boilerplate and require RxJS knowledge
Epics
Action
Reducers
View
Store
const doSomething = id => ({ type: SOME_ACTION, payload: id });
const doSomethingLogic = createLogic({
type: SOME_ACTION,
cancelType: SOME_ACTION_CANCEL,
process({ getState, action }, dispatch, done) {
fetch(/**/)
.then(data => dispatch({ type: SOME_ACTION_SUCCESS, payload: data }))
.catch(data => dispatch({ type: SOME_ACTION_FAILED, payload: data }))
.then(() => done());
}
});
Declarative API, supports everything mentioned before, easy supporf for complex cases, uses RxJS underneath.
Not very popular,
new API to learn
Logic
const doSomething = id => ({ type: SOME_ACTION, payload: id });
const doSomethingLogic = createLogic({
type: SOME_ACTION,
cancelType: SOME_ACTION_CANCEL,
processOptions: {
successType: SOME_ACTION_SUCCESS,
failType: SOME_ACTION_FAILED,
},
async process({ getState, action }) {
return await fetch(/**/);
}
});
View
Atoms
const somethingQuery = selectorFamily({
key: 'SomeData',
get: id => async () => {
const data = await fetch(/**/);
return data;
},
});
// in view
function ShowSomethingComponent({ id }) {
const data = useRecoilValue(somethingQuery(id));
return <div>{data}</div>;
}
Much simpler, high performance, very React-focused (concurrent mode etc.)
Is not production ready yet.
Not sure if it will handle complex business logic
Selectors
View
Stores
const useStore = create((set, get) => ({
someValue: {},
doSomething: async id => {
const data = await fetch(/**/);
set({ someValue: data });
}
});
// in view
function ShowSomethingComponent({ id }) {
const data = useStore(state => state.someValue);
return <div>{data}</div>;
}
Very simple but powerful.
Compatible with flux/redux architecture (devtools etc.)
Not very popular.
Not sure if it will handle complex business logic
Selectors
Action
flame war