tpai
7/21/2016 - 7:55 AM

Saga 的概念有點像 Event Loop,使用 take helpers 觀測 Trigger Action(load) 是否被 Dispatch,進而透過 Generator Function 使用 Call Effect 執行 Async Requests,再用 Put

Saga 的概念有點像 Event Loop,使用 take helpers 觀測 Trigger Action(load) 是否被 Dispatch,進而透過 Generator Function 使用 Call Effect 執行 Async Requests,再用 Put Effect 去 Dispatch 不同階段的 Action(loading, loaded, failed...) 以讓 UI 物件呈現出不同變化。

Learning Redux Saga With Simple Example

The concept of saga is like event loop, take effect/helpers for watching action, call effect for handling async request and put effect for dispatching different stage of actions(loading, loaded, failed...). Unlike thunk get invoked on every actions, saga only run once at the start and process watching in the background. About saga and thunk, two of the most common differences are async task could be cancelled at any moment, and the structure of saga is easy for developer to test different stage of actions.

###Flow

Update specific article title of list:

  1. Keep watching
  2. Component dispatch UPDATE_TITLE action
  3. Run updateTitle task(take effect)
  4. Call updateTitleAPI async request(call effect)
  5. Change to different stage UPDATE_TITLE_SUCCESS, UPDATE_TITLE_FAILED(put effect)
  6. Refresh list FETCH_LIST(fork effect)
  7. Reducer handle state
  8. Component display state
  9. Back to 1.

Thunk code will look like this:

const updateTitle = article => {
    return async dispatch => {
        dispatch({ type: UPDATE_TITLE });
        try {
            const res = await fetch(`url`, {
                method: 'PUT',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: {
                    title: article.title
                }
            });
            const json = await res.json();
            dispatch({ type: UPDATE_TITLE_SUCCESS });
        } catch(err) {
            dispatch({ type: UPDATE_TITLE_FAILED });
        }
    }
}

In saga, it will be

// action.updateTitle -> saga.watchUpdateTitle -> saga.updateTitle -> action.updateTitleAPI

// action
const updateTitleAPI = fetch(...).then(res => res.json());
const updateTitle = article => ({ type: UPDATE_TITLE, article });

// saga
function* updateTitle() {
    try {
        yield call(updateTitleAPI, action.article.title);
        yield put({ type: UPDATE_TITLE_SUCCESS });
        yield fork(fetchArticles);
    } catch(err) {
        yield put({ type: UPDATE_TITLE_FAILED });
    }
}
function* watchUpdateTitle() {
    yield takeLatest(UPDATE_TITLE, updateTitle);
}

Ref: