Redux: How to get access to data from a store?

Created on 17 Jul 2015  ·  8Comments  ·  Source: reduxjs/redux

I have read how to combine stores to exchange data between them

https://gist.github.com/gaearon/d77ca812015c0356654f

but I still wonder, how do I get access to what the state managed by a store programmatically? Maybe from a store, maybe from an action creator.

Example: You want to store an invoice to a server, but you need to get information about a user (id perhaps) from another store to do that.

I read on twitter

https://twitter.com/dan_abramov/status/621679403756601344

that you have to pass that information (id of user) along with the action. Does that mean the component will already get that information from a store an add it when it call the action creator?

I know this got a bit involved, I hope it still makes sense :)

help wanted question

Most helpful comment

Given the 1.0.0-rc version, in redux there is usually only one store, which is the instance you get from createStore().

The "flux stores" in redux are just reduce function, they don't hold any state.

If you return a function in the action creators, the arguments you get are dispatch and getState. The first one is used to dispatch your action object after an async operation, the second one is used to get some extra data from the store.

For example https://github.com/gaearon/redux/blob/breaking-changes-1.0/examples/counter/actions/CounterActions.js#L16

In your case it could look something like this:

function saveInvoice (data) {
  return (dispatch, getState) => {
    // get the user state
    const { user } = getState()

    fetch(invoiceUrl, {
      method: 'post',
      body: JSON.stringify({
        userId: user.id,
        invoice: data
      })
    })
    .then(res => res.json())
    .then(res => dispatch({
      type: 'INVOICE_SAVE',
      payload: res
    }))
  }
}

All 8 comments

Suppose, you already have the user details in the users store but not on the rendered component (invoice), to pass user_id with the save action (button click). One thing you can do is access the store's current state through connected component's this.context.store.getState()

Given the 1.0.0-rc version, in redux there is usually only one store, which is the instance you get from createStore().

The "flux stores" in redux are just reduce function, they don't hold any state.

If you return a function in the action creators, the arguments you get are dispatch and getState. The first one is used to dispatch your action object after an async operation, the second one is used to get some extra data from the store.

For example https://github.com/gaearon/redux/blob/breaking-changes-1.0/examples/counter/actions/CounterActions.js#L16

In your case it could look something like this:

function saveInvoice (data) {
  return (dispatch, getState) => {
    // get the user state
    const { user } = getState()

    fetch(invoiceUrl, {
      method: 'post',
      body: JSON.stringify({
        userId: user.id,
        invoice: data
      })
    })
    .then(res => res.json())
    .then(res => dispatch({
      type: 'INVOICE_SAVE',
      payload: res
    }))
  }
}

@emmenko if promise middleware is used, shouldn't you return the fetch request? Or is it implicit?

I'm not using the promise middleware here, just the thunk. You may want to have a look here for promise support.

Thanks to @tundrax and @emmenko, great answers.

To wrap up: I can

  • EITHER compose all the information I need in a controller component and pass it along as payload to the action
  • OR add the missing information in an action creator using getState that I get passed in from redux

Correct? If so: Do you have any preference which way yo use?

Both are OK and it depends on your specific use case.

For example if you have 10 controllers that look up identical information from the same state slice and pass it to action creator, it's easier to do this inside the action creator itself.

Finally, you can always have a “vanilla” action creator that just returns an action and accepts a parameter, and a “smarter” action creator that uses getState and calls dispatch(vanillaActionCreator(someParam, getState().something)).

It seems obvious to me that thunk callbacks should accept a single argument: the store.

The existing signature is easily changed to:

function myActionCreator() {
  return ({ dispatch, getState }) => {
    // ... do stuff ...
  };
}

But for things like redux-persist, we're able to access the store via actionCreators, e.g.

function purgePersistedState() {
  return (store) => {
    store.persistor.purge();
  };
}

How else are we supposed to expose store-related extensions to actions creators?

@jchook : not sure I understand your use case. What do you mean by "expose store-related extensions" ?

Also, note that redux-thunk is simply one possible middleware. You can certainly write your own custom middleware that passes in a different API to functions, although middleware don't actually get the "real" store reference - they get a wrapped/subset of the store API.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ilearnio picture ilearnio  ·  3Comments

benoneal picture benoneal  ·  3Comments

cloudfroster picture cloudfroster  ·  3Comments

CellOcean picture CellOcean  ·  3Comments

timdorr picture timdorr  ·  3Comments