sio-redux
v1.1.9
Published
Small redux library.
Downloads
11
Readme
sio-redux
A small library for managing the state of the application more easily
Concepts
Reducer
- The reducer is the place where the state it is managed
- The reducer is a function that receives 2 parameters:
- state which will have to be initialized the first time with the default operator from JS
- action will hold and object with the type of the action that we want and the payload if any
- All the time we have to produce a new state in order to be easy to reason about
- The state will be updated using the
switch case
features
const initialState: TState = {};
const reducer = (state = initialState, action: Action): TState => {
switch (action.type) {
case LoginActions.Authenticate:
return {
...state,
loading: false,
isAuthenticated: action.payload,
};
default:
return state;
}
};
Store
- The reducer will be used to create a store
- To create a store we can use the
createStore
function and send the reducer as argument - The
Store
will retun an object with 4 methods:dipatch
will be used to trigger the action that we needselect
will be used to subscribe to the store. It receives aSelector
as an argument an returns anObservable
getState
used for getting the current stateregisterEffects
used for registering effects that will handle impure actions like HTTP requests
const loginStore = createStore(reducer);
// to register some effects
loginStore.registerEffects(SomeEffects); // If there are no effects, no need to register
Selectors
- Selectors are functions where you specify what data you want to be returned
- When the state changes, only the already created selectors that we subscribed to will be notified.
- State changes in areas that we don't have selectors for, won't trigger a notification, this is performant and avoids hazard.
export const isAuthenticatedSelector = (state: LoginForm) =>
state.isAuthenticated;
Actions
- Actions are used to create a message in order to be used to communicate with the
Store
- Actions should have:
- type where a string representing the type of the action will be defined
- payload to hold some data to update the
Store
- When you need to trigger an action, just instantiate it and send the payload if necessary
enum LoginActions {
Authenticate = '[Login] authenticate Action'
}
export class AuthenticateAction {
type = LoginActions.Authenticate;
payload: boolean;
constructor(payload: boolean) {
this.payload = payload;
}
}
dispatch(new AuthenticateAction(true));
Effects
- Should be used only for asynchronous requests and should dispatch an
Action
in case we need to update the store - For actions that are impure, such as HTTP Request, this is the best place to act in order to keep the state clean.
export const getLoginEffects = (dispatch: (action: Action) => void) => {
return {
[LoginActions.Login]: (data: LoginForm) => {
fetch(
`http://localhost:5000/login?username=${data.username}&password=${data.password}`
)
.then((response) => response.json())
.then((response) => {
const action = response.success
? new AuthenticateAction(response.success)
: new ErrorAction(response.message);
dispatch(action);
})
.catch((response) => dispatch(new ErrorAction(response.message)));
},
};
};
- In the above example, we listen for a
Login
action and do an http request. - When the request is finised one of 2 actions can be triggered based on response.
How will be used
- Inside the component we have to import the store
- To subscribe to the store, use the
select
method
this.isLoading = loginStore.select((state: LoginForm) => state.isAuthenticate);
subscribing to the store can be done by assigning the returned observable to a variable and use the
async
pipe to subscribe and unsubscribeexplicit subscribe with
loginStore.select((state: LoginForm) => state.isAuthenticate).subscribe
the selector should be defined in the same file where the reducer lives in order to reuse the selector in other parts of the application
To dispatch an action can be done in any place of the application, depending on different scenarios
For Logging into an application an Authenticate action will be dispached from
Login
event listener
login(loginForm: LoginForm) {
loginStore
.dispatch(new LoginAction(loginForm));
}
- if the dispatch action will be called through
loginStore
object we can chain thedispatch
action for multiple actions
loginStore
.dispatch(new LoadingAction(true))
.dispatch(new LoginAction(loginForm));
dispatching multiple action can be useful but it should be used carefully
NOTE
if we use thedispatch
action in a different context than thestore.
,dispatch
will fail because thethis
keyword inside will refer toglobal
object.