How to get something from the state / store inside

2019-01-30 06:47发布

问题:

How do I access the redux state inside a saga function?

My Problem

I have an application consisting of the following parts:

            TOOLBAR        
 ---------------------------------
 User info     |   Current Project

Each part is a different component with it's own reducer, saga, actions and state.

The toolbar has a save button which dispatches a "SAVE_PROJECT" action type. The problem is that I don't want the toolbar to know the project (it has more responsibilities and I just want it to dispatch actions with type).

I have a project related saga which listens to the "SAVE_PROJECT":

...
export function* saveProjectTask() {
  while(true) {
    yield take(SAVE_PROJECT);
    let project = /* THIS IS THE PROBLEM, I DON'T HAVE THE PROJECT */;
    yield call(fetch, '/api/project', { body: project, method: 'PUT' });
    yield put({type: SAVE_PROJECT_SUCCESS});
  }
}

I can't get the project from the redux state inside the saga.

I don't think I can listen to the "SAVE_PROJECT" event inside the curren project reducer and then inside the reducer get the project and dispatch a different action with the project.

I really don't want my toolbar to know the entire state tree and send anything related to the action for every action.

How can I pass the state it-self to the saga? Or only the relevant part of the state?

回答1:

As @markerikson already says, redux-saga exposes a very useful API select() to invoke a selector on the state for getting some part of it available inside the saga.

For your example a simple implementation could be:

/*
 * Selector. The query depends by the state shape
 */
export const getProject = (state) => state.project

// Saga
export function* saveProjectTask() {
  while(true) {
    yield take(SAVE_PROJECT);
    let project = yield select(getProject); // <-- get the project
    yield call(fetch, '/api/project', { body: project, method: 'PUT' });
    yield put({type: SAVE_PROJECT_SUCCESS});
  }
}

In addition to the suggested doc by @markerikson, there is a very good video tutorial by D. Abramov which explains how to use selectors with Redux. Check also this interesting thread on Twitter.



回答2:

This is what "selector" functions are for. You pass them the entire state tree, and they return some piece of the state. The code that calls the selector doesn't need to know where in the state that data was, just that it was returned. See http://redux.js.org/docs/recipes/ComputingDerivedData.html for some examples.

Within a saga, the select() API can be used to execute a selector.