Redux

Redux is a predictable state container for JavaScript apps.
The whole state of your app is stored in an object tree inside a single store. The only way to change the state tree is to emit an action, an object describing what happened. To specify how the actions transform the state tree, you write pure reducers.

How dose Redux work?

  • Redux keep the whole state in an object tree in a single store.
  • The store need a reducer, reducer is a pure function that takes the current state, and an action, and returns the newState.
  • The only way to change the state tree is to emit an action by call dispatch. An action is a plain object with a property called type. Every call to dispatch results in a call to your reducer.
  • Other components can subscribe the state to refresh their view when the state changed.

Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { createStore } from 'redux'

const reducer = (state = {count: 0}, action) => {
switch (action.type){
case 'INCREASE': return {count: state.count + 1};
case 'DECREASE': return {count: state.count - 1};
default: return state;
}
}

const actions = {
increase: () => ({type: 'INCREASE'}),
decrease: () => ({type: 'DECREASE'})
}

const store = createStore(reducer);

store.subscribe(() =>
console.log(store.getState())
);

store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}

How to use Redux in React?

The react-redux library comes with 2 things: a component called Provider, and a function called connect.
By wrapping the entire app with the Provider component, every component in the app tree will be able to access the Redux store if it wants to.

1
2
3
<Provider store = {store}>
<App />
<Provider>

Connect is a higher-order function, which is a fancy way of saying it returns a function when you call it. And then calling that function with a component returns a new (wrapped) component.

Another name for this is a higher-order component (aka “HOC”). HOCs have gotten some bad press in the past, but it’s still quite a useful pattern, and connect is a good example of a useful one.

What connect does is hook into Redux, pull out the entire state, and pass it through the mapStateToProps function that you provide.

1
2
3
4
5
6
7
8
9
10
11
12
function mapStateToProps(state) {
return {
count: state.count
};
}

const mapDispatchToProps = {
increment,
decrement
};

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

redux-saga

redux-saga is a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage, more efficient to execute, easy to test, and better at handling failures.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'
import Api from '...'

// worker Saga: will be fired on USER_FETCH_REQUESTED actions
function* fetchUser(action) {
try {
const user = yield call(Api.fetchUser, action.payload.userId);
yield put({type: "USER_FETCH_SUCCEEDED", user: user});
} catch (e) {
yield put({type: "USER_FETCH_FAILED", message: e.message});
}
}

/*
Starts fetchUser on each dispatched `USER_FETCH_REQUESTED` action.
Allows concurrent fetches of user.
*/
function* mySaga() {
yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}

/*
Alternatively you may use takeLatest.

Does not allow concurrent fetches of user. If "USER_FETCH_REQUESTED" gets
dispatched while a fetch is already pending, that pending fetch is cancelled
and only the latest one will be run.
*/
function* mySaga() {
yield takeLatest("USER_FETCH_REQUESTED", fetchUser);
}

export default mySaga;

takeEvery() spawns a saga on each action dispatched to the Store that matches pattern.
takeLatest() forks a saga on each action dispatched to the Store that matches pattern and automatically cancels any previous saga task started previously if it’s still running.

Reference

reduxjs/redux
A Complete React Redux Tutorial for Beginners (2019)
redux-saga